From 8617586b3e089c8abb4a4095c22e0e6b806f32bb Mon Sep 17 00:00:00 2001 From: noti0na1 <8036790+noti0na1@users.noreply.github.com> Date: Wed, 20 Mar 2024 22:17:49 +0000 Subject: [PATCH 001/505] Skip widenSingletons in widenInferred if the inferred type is too large --- .../tools/dotc/core/ConstraintHandling.scala | 31 +- tests/pos/i19907/slow_1000_3.scala | 1024 ++++++++++++++++ tests/pos/i19907/slow_1000_4.scala | 1026 +++++++++++++++++ tests/pos/i19907/slow_100_3.scala | 124 ++ 4 files changed, 2200 insertions(+), 5 deletions(-) create mode 100644 tests/pos/i19907/slow_1000_3.scala create mode 100644 tests/pos/i19907/slow_1000_4.scala create mode 100644 tests/pos/i19907/slow_100_3.scala diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala index 0ceaaac75063..df20505e65ce 100644 --- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -657,11 +657,24 @@ trait ConstraintHandling { * as those could leak the annotation to users (see run/inferred-repeated-result). */ def widenInferred(inst: Type, bound: Type, widenUnions: Boolean)(using Context): Type = + def typeSize(tp: Type): Int = tp match + case tp: AndOrType => typeSize(tp.tp1) + typeSize(tp.tp2) + case _ => 1 + def widenOr(tp: Type) = if widenUnions then - val tpw = tp.widenUnion - if (tpw ne tp) && !isTransparent(tpw, traitOnly = false) && (tpw <:< bound) then tpw else tp - else tp.hardenUnions + val tpw = tp.widenUnion + if tpw ne tp then + if tpw.isTransparent() then + // Now also widen singletons of soft unions. Before these were skipped + // since we widenUnion on soft unions is independent of whether singletons + // are widened or not. This avoids an expensive subtype check in widenSingle, + // see 19907_*.scala for test cases. + tp.widenSingletons() + else if tpw <:< bound then tpw + else tp + else tp + else tp.hardenUnions def widenSingle(tp: Type) = val tpw = tp.widenSingletons @@ -674,8 +687,16 @@ trait ConstraintHandling { val wideInst = if isSingleton(bound) then inst else - val widenedFromSingle = widenSingle(inst) - val widenedFromUnion = widenOr(widenedFromSingle) + val widenedFromUnion = + if widenUnions && typeSize(inst) > 64 then + // If the inferred type `inst` is too large, the subtype check for `bound` in `widenSingle` + // can be expensive due to comparisons between large union types, so we avoid it by + // `widenUnion` directly here. + // See issue #19907. + widenOr(inst) + else + val widenedFromSingle = widenSingle(inst) + if widenUnions then widenOr(widenedFromSingle) else widenedFromSingle.hardenUnions val widened = dropTransparentTraits(widenedFromUnion, bound) widenIrreducible(widened) diff --git a/tests/pos/i19907/slow_1000_3.scala b/tests/pos/i19907/slow_1000_3.scala new file mode 100644 index 000000000000..5ed7d2f7e1bf --- /dev/null +++ b/tests/pos/i19907/slow_1000_3.scala @@ -0,0 +1,1024 @@ + + +abstract class ServerEndpoint[-R, F[_]] { + type T0 + type T1 + type T2 +} +object ServerEndpoint { + type Full[_T0, _T1, _T2, -R, F[_]] = + ServerEndpoint[R, F] { + type T0 = _T0 + type T1 = _T1 + type T2 = _T2 + } + def apply[_T0, _T1, _T2, R, F[_]]: ServerEndpoint.Full[_T0, _T1, _T2, R, F] = ??? +} + +object Test { + type Route = ServerEndpoint[Any, Option] + def routes: List[ServerEndpoint[Any, Option]] = { + val instance0 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance1 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance2 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance3 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance4 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance5 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance6 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance7 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance8 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance9 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance10 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance11 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance12 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance13 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance14 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance15 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance16 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance17 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance18 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance19 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance20 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance21 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance22 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance23 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance24 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance25 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance26 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance27 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance28 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance29 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance30 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance31 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance32 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance33 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance34 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance35 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance36 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance37 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance38 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance39 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance40 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance41 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance42 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance43 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance44 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance45 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance46 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance47 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance48 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance49 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance50 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance51 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance52 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance53 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance54 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance55 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance56 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance57 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance58 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance59 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance60 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance61 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance62 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance63 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance64 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance65 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance66 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance67 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance68 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance69 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance70 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance71 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance72 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance73 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance74 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance75 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance76 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance77 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance78 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance79 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance80 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance81 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance82 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance83 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance84 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance85 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance86 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance87 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance88 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance89 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance90 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance91 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance92 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance93 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance94 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance95 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance96 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance97 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance98 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance99 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance100 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance101 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance102 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance103 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance104 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance105 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance106 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance107 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance108 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance109 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance110 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance111 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance112 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance113 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance114 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance115 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance116 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance117 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance118 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance119 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance120 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance121 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance122 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance123 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance124 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance125 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance126 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance127 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance128 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance129 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance130 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance131 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance132 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance133 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance134 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance135 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance136 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance137 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance138 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance139 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance140 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance141 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance142 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance143 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance144 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance145 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance146 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance147 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance148 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance149 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance150 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance151 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance152 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance153 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance154 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance155 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance156 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance157 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance158 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance159 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance160 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance161 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance162 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance163 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance164 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance165 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance166 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance167 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance168 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance169 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance170 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance171 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance172 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance173 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance174 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance175 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance176 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance177 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance178 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance179 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance180 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance181 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance182 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance183 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance184 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance185 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance186 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance187 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance188 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance189 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance190 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance191 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance192 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance193 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance194 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance195 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance196 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance197 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance198 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance199 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance200 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance201 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance202 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance203 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance204 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance205 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance206 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance207 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance208 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance209 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance210 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance211 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance212 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance213 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance214 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance215 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance216 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance217 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance218 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance219 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance220 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance221 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance222 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance223 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance224 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance225 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance226 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance227 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance228 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance229 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance230 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance231 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance232 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance233 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance234 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance235 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance236 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance237 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance238 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance239 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance240 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance241 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance242 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance243 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance244 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance245 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance246 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance247 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance248 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance249 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance250 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance251 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance252 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance253 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance254 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance255 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance256 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance257 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance258 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance259 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance260 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance261 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance262 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance263 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance264 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance265 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance266 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance267 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance268 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance269 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance270 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance271 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance272 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance273 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance274 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance275 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance276 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance277 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance278 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance279 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance280 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance281 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance282 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance283 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance284 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance285 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance286 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance287 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance288 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance289 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance290 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance291 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance292 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance293 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance294 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance295 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance296 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance297 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance298 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance299 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance300 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance301 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance302 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance303 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance304 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance305 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance306 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance307 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance308 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance309 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance310 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance311 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance312 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance313 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance314 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance315 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance316 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance317 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance318 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance319 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance320 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance321 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance322 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance323 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance324 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance325 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance326 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance327 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance328 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance329 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance330 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance331 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance332 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance333 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance334 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance335 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance336 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance337 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance338 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance339 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance340 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance341 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance342 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance343 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance344 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance345 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance346 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance347 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance348 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance349 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance350 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance351 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance352 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance353 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance354 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance355 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance356 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance357 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance358 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance359 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance360 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance361 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance362 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance363 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance364 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance365 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance366 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance367 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance368 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance369 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance370 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance371 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance372 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance373 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance374 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance375 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance376 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance377 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance378 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance379 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance380 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance381 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance382 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance383 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance384 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance385 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance386 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance387 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance388 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance389 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance390 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance391 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance392 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance393 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance394 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance395 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance396 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance397 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance398 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance399 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance400 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance401 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance402 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance403 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance404 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance405 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance406 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance407 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance408 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance409 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance410 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance411 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance412 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance413 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance414 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance415 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance416 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance417 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance418 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance419 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance420 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance421 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance422 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance423 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance424 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance425 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance426 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance427 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance428 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance429 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance430 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance431 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance432 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance433 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance434 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance435 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance436 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance437 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance438 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance439 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance440 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance441 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance442 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance443 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance444 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance445 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance446 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance447 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance448 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance449 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance450 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance451 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance452 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance453 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance454 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance455 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance456 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance457 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance458 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance459 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance460 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance461 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance462 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance463 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance464 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance465 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance466 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance467 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance468 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance469 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance470 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance471 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance472 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance473 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance474 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance475 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance476 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance477 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance478 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance479 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance480 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance481 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance482 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance483 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance484 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance485 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance486 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance487 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance488 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance489 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance490 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance491 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance492 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance493 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance494 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance495 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance496 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance497 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance498 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance499 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance500 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance501 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance502 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance503 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance504 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance505 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance506 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance507 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance508 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance509 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance510 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance511 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance512 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance513 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance514 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance515 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance516 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance517 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance518 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance519 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance520 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance521 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance522 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance523 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance524 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance525 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance526 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance527 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance528 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance529 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance530 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance531 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance532 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance533 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance534 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance535 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance536 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance537 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance538 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance539 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance540 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance541 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance542 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance543 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance544 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance545 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance546 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance547 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance548 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance549 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance550 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance551 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance552 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance553 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance554 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance555 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance556 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance557 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance558 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance559 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance560 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance561 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance562 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance563 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance564 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance565 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance566 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance567 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance568 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance569 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance570 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance571 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance572 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance573 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance574 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance575 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance576 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance577 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance578 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance579 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance580 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance581 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance582 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance583 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance584 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance585 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance586 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance587 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance588 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance589 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance590 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance591 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance592 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance593 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance594 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance595 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance596 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance597 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance598 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance599 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance600 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance601 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance602 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance603 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance604 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance605 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance606 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance607 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance608 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance609 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance610 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance611 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance612 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance613 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance614 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance615 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance616 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance617 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance618 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance619 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance620 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance621 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance622 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance623 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance624 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance625 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance626 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance627 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance628 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance629 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance630 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance631 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance632 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance633 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance634 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance635 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance636 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance637 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance638 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance639 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance640 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance641 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance642 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance643 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance644 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance645 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance646 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance647 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance648 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance649 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance650 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance651 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance652 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance653 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance654 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance655 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance656 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance657 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance658 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance659 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance660 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance661 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance662 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance663 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance664 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance665 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance666 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance667 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance668 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance669 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance670 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance671 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance672 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance673 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance674 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance675 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance676 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance677 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance678 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance679 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance680 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance681 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance682 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance683 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance684 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance685 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance686 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance687 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance688 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance689 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance690 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance691 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance692 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance693 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance694 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance695 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance696 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance697 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance698 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance699 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance700 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance701 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance702 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance703 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance704 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance705 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance706 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance707 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance708 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance709 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance710 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance711 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance712 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance713 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance714 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance715 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance716 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance717 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance718 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance719 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance720 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance721 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance722 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance723 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance724 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance725 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance726 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance727 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance728 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance729 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance730 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance731 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance732 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance733 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance734 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance735 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance736 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance737 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance738 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance739 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance740 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance741 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance742 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance743 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance744 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance745 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance746 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance747 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance748 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance749 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance750 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance751 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance752 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance753 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance754 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance755 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance756 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance757 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance758 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance759 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance760 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance761 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance762 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance763 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance764 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance765 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance766 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance767 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance768 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance769 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance770 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance771 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance772 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance773 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance774 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance775 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance776 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance777 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance778 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance779 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance780 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance781 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance782 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance783 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance784 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance785 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance786 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance787 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance788 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance789 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance790 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance791 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance792 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance793 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance794 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance795 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance796 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance797 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance798 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance799 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance800 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance801 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance802 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance803 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance804 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance805 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance806 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance807 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance808 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance809 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance810 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance811 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance812 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance813 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance814 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance815 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance816 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance817 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance818 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance819 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance820 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance821 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance822 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance823 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance824 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance825 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance826 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance827 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance828 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance829 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance830 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance831 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance832 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance833 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance834 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance835 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance836 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance837 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance838 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance839 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance840 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance841 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance842 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance843 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance844 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance845 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance846 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance847 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance848 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance849 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance850 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance851 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance852 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance853 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance854 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance855 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance856 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance857 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance858 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance859 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance860 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance861 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance862 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance863 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance864 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance865 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance866 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance867 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance868 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance869 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance870 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance871 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance872 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance873 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance874 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance875 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance876 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance877 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance878 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance879 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance880 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance881 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance882 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance883 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance884 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance885 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance886 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance887 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance888 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance889 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance890 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance891 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance892 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance893 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance894 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance895 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance896 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance897 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance898 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance899 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance900 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance901 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance902 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance903 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance904 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance905 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance906 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance907 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance908 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance909 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance910 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance911 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance912 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance913 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance914 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance915 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance916 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance917 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance918 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance919 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance920 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance921 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance922 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance923 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance924 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance925 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance926 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance927 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance928 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance929 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance930 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance931 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance932 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance933 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance934 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance935 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance936 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance937 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance938 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance939 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance940 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance941 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance942 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance943 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance944 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance945 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance946 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance947 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance948 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance949 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance950 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance951 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance952 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance953 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance954 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance955 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance956 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance957 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance958 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance959 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance960 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance961 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance962 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance963 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance964 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance965 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance966 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance967 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance968 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance969 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance970 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance971 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance972 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance973 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance974 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance975 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance976 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance977 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance978 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance979 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance980 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance981 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance982 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance983 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance984 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance985 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance986 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance987 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance988 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance989 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance990 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance991 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance992 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance993 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance994 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance995 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance996 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance997 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance998 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance999 = ServerEndpoint[Unit, Unit, Int, Any, Option] + List(instance0, instance1, instance2, instance3, instance4, instance5, instance6, instance7, instance8, instance9, instance10, instance11, instance12, instance13, instance14, instance15, instance16, instance17, instance18, instance19, instance20, instance21, instance22, instance23, instance24, instance25, instance26, instance27, instance28, instance29, instance30, instance31, instance32, instance33, instance34, instance35, instance36, instance37, instance38, instance39, instance40, instance41, instance42, instance43, instance44, instance45, instance46, instance47, instance48, instance49, instance50, instance51, instance52, instance53, instance54, instance55, instance56, instance57, instance58, instance59, instance60, instance61, instance62, instance63, instance64, instance65, instance66, instance67, instance68, instance69, instance70, instance71, instance72, instance73, instance74, instance75, instance76, instance77, instance78, instance79, instance80, instance81, instance82, instance83, instance84, instance85, instance86, instance87, instance88, instance89, instance90, instance91, instance92, instance93, instance94, instance95, instance96, instance97, instance98, instance99, instance100, instance101, instance102, instance103, instance104, instance105, instance106, instance107, instance108, instance109, instance110, instance111, instance112, instance113, instance114, instance115, instance116, instance117, instance118, instance119, instance120, instance121, instance122, instance123, instance124, instance125, instance126, instance127, instance128, instance129, instance130, instance131, instance132, instance133, instance134, instance135, instance136, instance137, instance138, instance139, instance140, instance141, instance142, instance143, instance144, instance145, instance146, instance147, instance148, instance149, instance150, instance151, instance152, instance153, instance154, instance155, instance156, instance157, instance158, instance159, instance160, instance161, instance162, instance163, instance164, instance165, instance166, instance167, instance168, instance169, instance170, instance171, instance172, instance173, instance174, instance175, instance176, instance177, instance178, instance179, instance180, instance181, instance182, instance183, instance184, instance185, instance186, instance187, instance188, instance189, instance190, instance191, instance192, instance193, instance194, instance195, instance196, instance197, instance198, instance199, instance200, instance201, instance202, instance203, instance204, instance205, instance206, instance207, instance208, instance209, instance210, instance211, instance212, instance213, instance214, instance215, instance216, instance217, instance218, instance219, instance220, instance221, instance222, instance223, instance224, instance225, instance226, instance227, instance228, instance229, instance230, instance231, instance232, instance233, instance234, instance235, instance236, instance237, instance238, instance239, instance240, instance241, instance242, instance243, instance244, instance245, instance246, instance247, instance248, instance249, instance250, instance251, instance252, instance253, instance254, instance255, instance256, instance257, instance258, instance259, instance260, instance261, instance262, instance263, instance264, instance265, instance266, instance267, instance268, instance269, instance270, instance271, instance272, instance273, instance274, instance275, instance276, instance277, instance278, instance279, instance280, instance281, instance282, instance283, instance284, instance285, instance286, instance287, instance288, instance289, instance290, instance291, instance292, instance293, instance294, instance295, instance296, instance297, instance298, instance299, instance300, instance301, instance302, instance303, instance304, instance305, instance306, instance307, instance308, instance309, instance310, instance311, instance312, instance313, instance314, instance315, instance316, instance317, instance318, instance319, instance320, instance321, instance322, instance323, instance324, instance325, instance326, instance327, instance328, instance329, instance330, instance331, instance332, instance333, instance334, instance335, instance336, instance337, instance338, instance339, instance340, instance341, instance342, instance343, instance344, instance345, instance346, instance347, instance348, instance349, instance350, instance351, instance352, instance353, instance354, instance355, instance356, instance357, instance358, instance359, instance360, instance361, instance362, instance363, instance364, instance365, instance366, instance367, instance368, instance369, instance370, instance371, instance372, instance373, instance374, instance375, instance376, instance377, instance378, instance379, instance380, instance381, instance382, instance383, instance384, instance385, instance386, instance387, instance388, instance389, instance390, instance391, instance392, instance393, instance394, instance395, instance396, instance397, instance398, instance399, instance400, instance401, instance402, instance403, instance404, instance405, instance406, instance407, instance408, instance409, instance410, instance411, instance412, instance413, instance414, instance415, instance416, instance417, instance418, instance419, instance420, instance421, instance422, instance423, instance424, instance425, instance426, instance427, instance428, instance429, instance430, instance431, instance432, instance433, instance434, instance435, instance436, instance437, instance438, instance439, instance440, instance441, instance442, instance443, instance444, instance445, instance446, instance447, instance448, instance449, instance450, instance451, instance452, instance453, instance454, instance455, instance456, instance457, instance458, instance459, instance460, instance461, instance462, instance463, instance464, instance465, instance466, instance467, instance468, instance469, instance470, instance471, instance472, instance473, instance474, instance475, instance476, instance477, instance478, instance479, instance480, instance481, instance482, instance483, instance484, instance485, instance486, instance487, instance488, instance489, instance490, instance491, instance492, instance493, instance494, instance495, instance496, instance497, instance498, instance499, instance500, instance501, instance502, instance503, instance504, instance505, instance506, instance507, instance508, instance509, instance510, instance511, instance512, instance513, instance514, instance515, instance516, instance517, instance518, instance519, instance520, instance521, instance522, instance523, instance524, instance525, instance526, instance527, instance528, instance529, instance530, instance531, instance532, instance533, instance534, instance535, instance536, instance537, instance538, instance539, instance540, instance541, instance542, instance543, instance544, instance545, instance546, instance547, instance548, instance549, instance550, instance551, instance552, instance553, instance554, instance555, instance556, instance557, instance558, instance559, instance560, instance561, instance562, instance563, instance564, instance565, instance566, instance567, instance568, instance569, instance570, instance571, instance572, instance573, instance574, instance575, instance576, instance577, instance578, instance579, instance580, instance581, instance582, instance583, instance584, instance585, instance586, instance587, instance588, instance589, instance590, instance591, instance592, instance593, instance594, instance595, instance596, instance597, instance598, instance599, instance600, instance601, instance602, instance603, instance604, instance605, instance606, instance607, instance608, instance609, instance610, instance611, instance612, instance613, instance614, instance615, instance616, instance617, instance618, instance619, instance620, instance621, instance622, instance623, instance624, instance625, instance626, instance627, instance628, instance629, instance630, instance631, instance632, instance633, instance634, instance635, instance636, instance637, instance638, instance639, instance640, instance641, instance642, instance643, instance644, instance645, instance646, instance647, instance648, instance649, instance650, instance651, instance652, instance653, instance654, instance655, instance656, instance657, instance658, instance659, instance660, instance661, instance662, instance663, instance664, instance665, instance666, instance667, instance668, instance669, instance670, instance671, instance672, instance673, instance674, instance675, instance676, instance677, instance678, instance679, instance680, instance681, instance682, instance683, instance684, instance685, instance686, instance687, instance688, instance689, instance690, instance691, instance692, instance693, instance694, instance695, instance696, instance697, instance698, instance699, instance700, instance701, instance702, instance703, instance704, instance705, instance706, instance707, instance708, instance709, instance710, instance711, instance712, instance713, instance714, instance715, instance716, instance717, instance718, instance719, instance720, instance721, instance722, instance723, instance724, instance725, instance726, instance727, instance728, instance729, instance730, instance731, instance732, instance733, instance734, instance735, instance736, instance737, instance738, instance739, instance740, instance741, instance742, instance743, instance744, instance745, instance746, instance747, instance748, instance749, instance750, instance751, instance752, instance753, instance754, instance755, instance756, instance757, instance758, instance759, instance760, instance761, instance762, instance763, instance764, instance765, instance766, instance767, instance768, instance769, instance770, instance771, instance772, instance773, instance774, instance775, instance776, instance777, instance778, instance779, instance780, instance781, instance782, instance783, instance784, instance785, instance786, instance787, instance788, instance789, instance790, instance791, instance792, instance793, instance794, instance795, instance796, instance797, instance798, instance799, instance800, instance801, instance802, instance803, instance804, instance805, instance806, instance807, instance808, instance809, instance810, instance811, instance812, instance813, instance814, instance815, instance816, instance817, instance818, instance819, instance820, instance821, instance822, instance823, instance824, instance825, instance826, instance827, instance828, instance829, instance830, instance831, instance832, instance833, instance834, instance835, instance836, instance837, instance838, instance839, instance840, instance841, instance842, instance843, instance844, instance845, instance846, instance847, instance848, instance849, instance850, instance851, instance852, instance853, instance854, instance855, instance856, instance857, instance858, instance859, instance860, instance861, instance862, instance863, instance864, instance865, instance866, instance867, instance868, instance869, instance870, instance871, instance872, instance873, instance874, instance875, instance876, instance877, instance878, instance879, instance880, instance881, instance882, instance883, instance884, instance885, instance886, instance887, instance888, instance889, instance890, instance891, instance892, instance893, instance894, instance895, instance896, instance897, instance898, instance899, instance900, instance901, instance902, instance903, instance904, instance905, instance906, instance907, instance908, instance909, instance910, instance911, instance912, instance913, instance914, instance915, instance916, instance917, instance918, instance919, instance920, instance921, instance922, instance923, instance924, instance925, instance926, instance927, instance928, instance929, instance930, instance931, instance932, instance933, instance934, instance935, instance936, instance937, instance938, instance939, instance940, instance941, instance942, instance943, instance944, instance945, instance946, instance947, instance948, instance949, instance950, instance951, instance952, instance953, instance954, instance955, instance956, instance957, instance958, instance959, instance960, instance961, instance962, instance963, instance964, instance965, instance966, instance967, instance968, instance969, instance970, instance971, instance972, instance973, instance974, instance975, instance976, instance977, instance978, instance979, instance980, instance981, instance982, instance983, instance984, instance985, instance986, instance987, instance988, instance989, instance990, instance991, instance992, instance993, instance994, instance995, instance996, instance997, instance998, instance999) + } +} + diff --git a/tests/pos/i19907/slow_1000_4.scala b/tests/pos/i19907/slow_1000_4.scala new file mode 100644 index 000000000000..231bfadc9354 --- /dev/null +++ b/tests/pos/i19907/slow_1000_4.scala @@ -0,0 +1,1026 @@ + + +abstract class ServerEndpoint[-R, F[_]] { + type T0 + type T1 + type T2 + type T3 +} +object ServerEndpoint { + type Full[_T0, _T1, _T2, _T3, -R, F[_]] = + ServerEndpoint[R, F] { + type T0 = _T0 + type T1 = _T1 + type T2 = _T2 + type T3 = _T3 + } + def apply[_T0, _T1, _T2, _T3, R, F[_]]: ServerEndpoint.Full[_T0, _T1, _T2, _T3, R, F] = ??? +} + +object Test { + type Route = ServerEndpoint[Any, Option] + def routes: List[ServerEndpoint[Any, Option]] = { + val instance0 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance1 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance2 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance3 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance4 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance5 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance6 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance7 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance8 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance9 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance10 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance11 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance12 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance13 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance14 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance15 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance16 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance17 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance18 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance19 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance20 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance21 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance22 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance23 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance24 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance25 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance26 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance27 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance28 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance29 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance30 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance31 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance32 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance33 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance34 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance35 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance36 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance37 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance38 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance39 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance40 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance41 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance42 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance43 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance44 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance45 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance46 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance47 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance48 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance49 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance50 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance51 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance52 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance53 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance54 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance55 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance56 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance57 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance58 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance59 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance60 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance61 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance62 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance63 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance64 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance65 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance66 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance67 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance68 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance69 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance70 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance71 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance72 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance73 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance74 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance75 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance76 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance77 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance78 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance79 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance80 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance81 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance82 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance83 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance84 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance85 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance86 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance87 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance88 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance89 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance90 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance91 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance92 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance93 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance94 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance95 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance96 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance97 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance98 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance99 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance100 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance101 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance102 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance103 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance104 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance105 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance106 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance107 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance108 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance109 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance110 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance111 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance112 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance113 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance114 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance115 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance116 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance117 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance118 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance119 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance120 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance121 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance122 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance123 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance124 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance125 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance126 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance127 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance128 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance129 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance130 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance131 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance132 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance133 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance134 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance135 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance136 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance137 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance138 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance139 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance140 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance141 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance142 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance143 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance144 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance145 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance146 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance147 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance148 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance149 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance150 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance151 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance152 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance153 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance154 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance155 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance156 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance157 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance158 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance159 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance160 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance161 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance162 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance163 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance164 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance165 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance166 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance167 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance168 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance169 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance170 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance171 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance172 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance173 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance174 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance175 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance176 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance177 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance178 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance179 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance180 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance181 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance182 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance183 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance184 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance185 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance186 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance187 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance188 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance189 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance190 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance191 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance192 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance193 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance194 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance195 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance196 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance197 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance198 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance199 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance200 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance201 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance202 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance203 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance204 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance205 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance206 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance207 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance208 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance209 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance210 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance211 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance212 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance213 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance214 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance215 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance216 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance217 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance218 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance219 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance220 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance221 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance222 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance223 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance224 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance225 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance226 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance227 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance228 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance229 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance230 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance231 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance232 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance233 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance234 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance235 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance236 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance237 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance238 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance239 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance240 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance241 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance242 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance243 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance244 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance245 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance246 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance247 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance248 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance249 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance250 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance251 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance252 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance253 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance254 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance255 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance256 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance257 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance258 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance259 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance260 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance261 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance262 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance263 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance264 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance265 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance266 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance267 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance268 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance269 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance270 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance271 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance272 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance273 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance274 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance275 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance276 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance277 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance278 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance279 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance280 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance281 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance282 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance283 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance284 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance285 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance286 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance287 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance288 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance289 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance290 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance291 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance292 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance293 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance294 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance295 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance296 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance297 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance298 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance299 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance300 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance301 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance302 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance303 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance304 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance305 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance306 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance307 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance308 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance309 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance310 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance311 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance312 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance313 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance314 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance315 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance316 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance317 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance318 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance319 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance320 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance321 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance322 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance323 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance324 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance325 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance326 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance327 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance328 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance329 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance330 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance331 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance332 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance333 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance334 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance335 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance336 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance337 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance338 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance339 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance340 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance341 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance342 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance343 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance344 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance345 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance346 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance347 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance348 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance349 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance350 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance351 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance352 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance353 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance354 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance355 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance356 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance357 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance358 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance359 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance360 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance361 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance362 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance363 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance364 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance365 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance366 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance367 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance368 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance369 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance370 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance371 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance372 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance373 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance374 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance375 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance376 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance377 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance378 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance379 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance380 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance381 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance382 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance383 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance384 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance385 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance386 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance387 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance388 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance389 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance390 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance391 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance392 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance393 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance394 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance395 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance396 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance397 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance398 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance399 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance400 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance401 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance402 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance403 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance404 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance405 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance406 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance407 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance408 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance409 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance410 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance411 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance412 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance413 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance414 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance415 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance416 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance417 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance418 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance419 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance420 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance421 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance422 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance423 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance424 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance425 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance426 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance427 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance428 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance429 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance430 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance431 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance432 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance433 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance434 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance435 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance436 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance437 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance438 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance439 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance440 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance441 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance442 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance443 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance444 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance445 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance446 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance447 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance448 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance449 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance450 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance451 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance452 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance453 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance454 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance455 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance456 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance457 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance458 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance459 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance460 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance461 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance462 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance463 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance464 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance465 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance466 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance467 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance468 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance469 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance470 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance471 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance472 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance473 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance474 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance475 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance476 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance477 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance478 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance479 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance480 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance481 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance482 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance483 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance484 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance485 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance486 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance487 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance488 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance489 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance490 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance491 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance492 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance493 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance494 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance495 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance496 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance497 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance498 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance499 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance500 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance501 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance502 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance503 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance504 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance505 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance506 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance507 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance508 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance509 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance510 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance511 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance512 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance513 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance514 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance515 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance516 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance517 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance518 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance519 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance520 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance521 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance522 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance523 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance524 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance525 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance526 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance527 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance528 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance529 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance530 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance531 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance532 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance533 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance534 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance535 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance536 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance537 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance538 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance539 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance540 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance541 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance542 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance543 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance544 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance545 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance546 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance547 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance548 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance549 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance550 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance551 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance552 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance553 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance554 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance555 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance556 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance557 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance558 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance559 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance560 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance561 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance562 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance563 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance564 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance565 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance566 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance567 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance568 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance569 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance570 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance571 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance572 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance573 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance574 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance575 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance576 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance577 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance578 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance579 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance580 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance581 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance582 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance583 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance584 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance585 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance586 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance587 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance588 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance589 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance590 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance591 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance592 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance593 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance594 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance595 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance596 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance597 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance598 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance599 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance600 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance601 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance602 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance603 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance604 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance605 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance606 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance607 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance608 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance609 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance610 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance611 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance612 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance613 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance614 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance615 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance616 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance617 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance618 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance619 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance620 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance621 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance622 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance623 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance624 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance625 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance626 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance627 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance628 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance629 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance630 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance631 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance632 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance633 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance634 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance635 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance636 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance637 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance638 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance639 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance640 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance641 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance642 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance643 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance644 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance645 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance646 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance647 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance648 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance649 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance650 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance651 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance652 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance653 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance654 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance655 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance656 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance657 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance658 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance659 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance660 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance661 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance662 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance663 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance664 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance665 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance666 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance667 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance668 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance669 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance670 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance671 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance672 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance673 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance674 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance675 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance676 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance677 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance678 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance679 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance680 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance681 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance682 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance683 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance684 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance685 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance686 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance687 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance688 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance689 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance690 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance691 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance692 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance693 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance694 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance695 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance696 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance697 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance698 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance699 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance700 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance701 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance702 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance703 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance704 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance705 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance706 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance707 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance708 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance709 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance710 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance711 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance712 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance713 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance714 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance715 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance716 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance717 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance718 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance719 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance720 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance721 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance722 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance723 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance724 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance725 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance726 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance727 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance728 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance729 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance730 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance731 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance732 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance733 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance734 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance735 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance736 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance737 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance738 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance739 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance740 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance741 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance742 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance743 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance744 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance745 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance746 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance747 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance748 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance749 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance750 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance751 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance752 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance753 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance754 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance755 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance756 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance757 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance758 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance759 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance760 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance761 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance762 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance763 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance764 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance765 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance766 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance767 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance768 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance769 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance770 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance771 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance772 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance773 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance774 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance775 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance776 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance777 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance778 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance779 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance780 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance781 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance782 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance783 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance784 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance785 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance786 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance787 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance788 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance789 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance790 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance791 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance792 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance793 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance794 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance795 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance796 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance797 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance798 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance799 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance800 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance801 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance802 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance803 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance804 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance805 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance806 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance807 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance808 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance809 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance810 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance811 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance812 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance813 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance814 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance815 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance816 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance817 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance818 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance819 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance820 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance821 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance822 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance823 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance824 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance825 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance826 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance827 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance828 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance829 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance830 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance831 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance832 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance833 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance834 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance835 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance836 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance837 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance838 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance839 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance840 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance841 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance842 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance843 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance844 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance845 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance846 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance847 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance848 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance849 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance850 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance851 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance852 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance853 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance854 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance855 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance856 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance857 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance858 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance859 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance860 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance861 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance862 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance863 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance864 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance865 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance866 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance867 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance868 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance869 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance870 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance871 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance872 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance873 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance874 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance875 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance876 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance877 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance878 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance879 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance880 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance881 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance882 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance883 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance884 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance885 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance886 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance887 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance888 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance889 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance890 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance891 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance892 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance893 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance894 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance895 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance896 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance897 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance898 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance899 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance900 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance901 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance902 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance903 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance904 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance905 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance906 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance907 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance908 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance909 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance910 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance911 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance912 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance913 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance914 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance915 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance916 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance917 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance918 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance919 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance920 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance921 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance922 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance923 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance924 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance925 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance926 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance927 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance928 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance929 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance930 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance931 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance932 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance933 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance934 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance935 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance936 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance937 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance938 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance939 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance940 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance941 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance942 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance943 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance944 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance945 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance946 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance947 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance948 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance949 = ServerEndpoint[Unit, Unit, Int, Unit, Any, Option] + val instance950 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance951 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance952 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance953 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance954 = ServerEndpoint[Int, Int, Unit, Int, Any, Option] + val instance955 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance956 = ServerEndpoint[Int, Unit, Int, Unit, Any, Option] + val instance957 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance958 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance959 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance960 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance961 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance962 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance963 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance964 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance965 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance966 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance967 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance968 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance969 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance970 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance971 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + val instance972 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance973 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance974 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance975 = ServerEndpoint[Int, Int, Int, Int, Any, Option] + val instance976 = ServerEndpoint[Unit, Int, Int, Int, Any, Option] + val instance977 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance978 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance979 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance980 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance981 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance982 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance983 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance984 = ServerEndpoint[Unit, Unit, Int, Int, Any, Option] + val instance985 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance986 = ServerEndpoint[Unit, Int, Unit, Unit, Any, Option] + val instance987 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance988 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance989 = ServerEndpoint[Int, Unit, Unit, Unit, Any, Option] + val instance990 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance991 = ServerEndpoint[Unit, Int, Int, Unit, Any, Option] + val instance992 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance993 = ServerEndpoint[Unit, Int, Unit, Int, Any, Option] + val instance994 = ServerEndpoint[Int, Int, Unit, Unit, Any, Option] + val instance995 = ServerEndpoint[Unit, Unit, Unit, Int, Any, Option] + val instance996 = ServerEndpoint[Int, Unit, Unit, Int, Any, Option] + val instance997 = ServerEndpoint[Unit, Unit, Unit, Unit, Any, Option] + val instance998 = ServerEndpoint[Int, Unit, Int, Int, Any, Option] + val instance999 = ServerEndpoint[Int, Int, Int, Unit, Any, Option] + List(instance0, instance1, instance2, instance3, instance4, instance5, instance6, instance7, instance8, instance9, instance10, instance11, instance12, instance13, instance14, instance15, instance16, instance17, instance18, instance19, instance20, instance21, instance22, instance23, instance24, instance25, instance26, instance27, instance28, instance29, instance30, instance31, instance32, instance33, instance34, instance35, instance36, instance37, instance38, instance39, instance40, instance41, instance42, instance43, instance44, instance45, instance46, instance47, instance48, instance49, instance50, instance51, instance52, instance53, instance54, instance55, instance56, instance57, instance58, instance59, instance60, instance61, instance62, instance63, instance64, instance65, instance66, instance67, instance68, instance69, instance70, instance71, instance72, instance73, instance74, instance75, instance76, instance77, instance78, instance79, instance80, instance81, instance82, instance83, instance84, instance85, instance86, instance87, instance88, instance89, instance90, instance91, instance92, instance93, instance94, instance95, instance96, instance97, instance98, instance99, instance100, instance101, instance102, instance103, instance104, instance105, instance106, instance107, instance108, instance109, instance110, instance111, instance112, instance113, instance114, instance115, instance116, instance117, instance118, instance119, instance120, instance121, instance122, instance123, instance124, instance125, instance126, instance127, instance128, instance129, instance130, instance131, instance132, instance133, instance134, instance135, instance136, instance137, instance138, instance139, instance140, instance141, instance142, instance143, instance144, instance145, instance146, instance147, instance148, instance149, instance150, instance151, instance152, instance153, instance154, instance155, instance156, instance157, instance158, instance159, instance160, instance161, instance162, instance163, instance164, instance165, instance166, instance167, instance168, instance169, instance170, instance171, instance172, instance173, instance174, instance175, instance176, instance177, instance178, instance179, instance180, instance181, instance182, instance183, instance184, instance185, instance186, instance187, instance188, instance189, instance190, instance191, instance192, instance193, instance194, instance195, instance196, instance197, instance198, instance199, instance200, instance201, instance202, instance203, instance204, instance205, instance206, instance207, instance208, instance209, instance210, instance211, instance212, instance213, instance214, instance215, instance216, instance217, instance218, instance219, instance220, instance221, instance222, instance223, instance224, instance225, instance226, instance227, instance228, instance229, instance230, instance231, instance232, instance233, instance234, instance235, instance236, instance237, instance238, instance239, instance240, instance241, instance242, instance243, instance244, instance245, instance246, instance247, instance248, instance249, instance250, instance251, instance252, instance253, instance254, instance255, instance256, instance257, instance258, instance259, instance260, instance261, instance262, instance263, instance264, instance265, instance266, instance267, instance268, instance269, instance270, instance271, instance272, instance273, instance274, instance275, instance276, instance277, instance278, instance279, instance280, instance281, instance282, instance283, instance284, instance285, instance286, instance287, instance288, instance289, instance290, instance291, instance292, instance293, instance294, instance295, instance296, instance297, instance298, instance299, instance300, instance301, instance302, instance303, instance304, instance305, instance306, instance307, instance308, instance309, instance310, instance311, instance312, instance313, instance314, instance315, instance316, instance317, instance318, instance319, instance320, instance321, instance322, instance323, instance324, instance325, instance326, instance327, instance328, instance329, instance330, instance331, instance332, instance333, instance334, instance335, instance336, instance337, instance338, instance339, instance340, instance341, instance342, instance343, instance344, instance345, instance346, instance347, instance348, instance349, instance350, instance351, instance352, instance353, instance354, instance355, instance356, instance357, instance358, instance359, instance360, instance361, instance362, instance363, instance364, instance365, instance366, instance367, instance368, instance369, instance370, instance371, instance372, instance373, instance374, instance375, instance376, instance377, instance378, instance379, instance380, instance381, instance382, instance383, instance384, instance385, instance386, instance387, instance388, instance389, instance390, instance391, instance392, instance393, instance394, instance395, instance396, instance397, instance398, instance399, instance400, instance401, instance402, instance403, instance404, instance405, instance406, instance407, instance408, instance409, instance410, instance411, instance412, instance413, instance414, instance415, instance416, instance417, instance418, instance419, instance420, instance421, instance422, instance423, instance424, instance425, instance426, instance427, instance428, instance429, instance430, instance431, instance432, instance433, instance434, instance435, instance436, instance437, instance438, instance439, instance440, instance441, instance442, instance443, instance444, instance445, instance446, instance447, instance448, instance449, instance450, instance451, instance452, instance453, instance454, instance455, instance456, instance457, instance458, instance459, instance460, instance461, instance462, instance463, instance464, instance465, instance466, instance467, instance468, instance469, instance470, instance471, instance472, instance473, instance474, instance475, instance476, instance477, instance478, instance479, instance480, instance481, instance482, instance483, instance484, instance485, instance486, instance487, instance488, instance489, instance490, instance491, instance492, instance493, instance494, instance495, instance496, instance497, instance498, instance499, instance500, instance501, instance502, instance503, instance504, instance505, instance506, instance507, instance508, instance509, instance510, instance511, instance512, instance513, instance514, instance515, instance516, instance517, instance518, instance519, instance520, instance521, instance522, instance523, instance524, instance525, instance526, instance527, instance528, instance529, instance530, instance531, instance532, instance533, instance534, instance535, instance536, instance537, instance538, instance539, instance540, instance541, instance542, instance543, instance544, instance545, instance546, instance547, instance548, instance549, instance550, instance551, instance552, instance553, instance554, instance555, instance556, instance557, instance558, instance559, instance560, instance561, instance562, instance563, instance564, instance565, instance566, instance567, instance568, instance569, instance570, instance571, instance572, instance573, instance574, instance575, instance576, instance577, instance578, instance579, instance580, instance581, instance582, instance583, instance584, instance585, instance586, instance587, instance588, instance589, instance590, instance591, instance592, instance593, instance594, instance595, instance596, instance597, instance598, instance599, instance600, instance601, instance602, instance603, instance604, instance605, instance606, instance607, instance608, instance609, instance610, instance611, instance612, instance613, instance614, instance615, instance616, instance617, instance618, instance619, instance620, instance621, instance622, instance623, instance624, instance625, instance626, instance627, instance628, instance629, instance630, instance631, instance632, instance633, instance634, instance635, instance636, instance637, instance638, instance639, instance640, instance641, instance642, instance643, instance644, instance645, instance646, instance647, instance648, instance649, instance650, instance651, instance652, instance653, instance654, instance655, instance656, instance657, instance658, instance659, instance660, instance661, instance662, instance663, instance664, instance665, instance666, instance667, instance668, instance669, instance670, instance671, instance672, instance673, instance674, instance675, instance676, instance677, instance678, instance679, instance680, instance681, instance682, instance683, instance684, instance685, instance686, instance687, instance688, instance689, instance690, instance691, instance692, instance693, instance694, instance695, instance696, instance697, instance698, instance699, instance700, instance701, instance702, instance703, instance704, instance705, instance706, instance707, instance708, instance709, instance710, instance711, instance712, instance713, instance714, instance715, instance716, instance717, instance718, instance719, instance720, instance721, instance722, instance723, instance724, instance725, instance726, instance727, instance728, instance729, instance730, instance731, instance732, instance733, instance734, instance735, instance736, instance737, instance738, instance739, instance740, instance741, instance742, instance743, instance744, instance745, instance746, instance747, instance748, instance749, instance750, instance751, instance752, instance753, instance754, instance755, instance756, instance757, instance758, instance759, instance760, instance761, instance762, instance763, instance764, instance765, instance766, instance767, instance768, instance769, instance770, instance771, instance772, instance773, instance774, instance775, instance776, instance777, instance778, instance779, instance780, instance781, instance782, instance783, instance784, instance785, instance786, instance787, instance788, instance789, instance790, instance791, instance792, instance793, instance794, instance795, instance796, instance797, instance798, instance799, instance800, instance801, instance802, instance803, instance804, instance805, instance806, instance807, instance808, instance809, instance810, instance811, instance812, instance813, instance814, instance815, instance816, instance817, instance818, instance819, instance820, instance821, instance822, instance823, instance824, instance825, instance826, instance827, instance828, instance829, instance830, instance831, instance832, instance833, instance834, instance835, instance836, instance837, instance838, instance839, instance840, instance841, instance842, instance843, instance844, instance845, instance846, instance847, instance848, instance849, instance850, instance851, instance852, instance853, instance854, instance855, instance856, instance857, instance858, instance859, instance860, instance861, instance862, instance863, instance864, instance865, instance866, instance867, instance868, instance869, instance870, instance871, instance872, instance873, instance874, instance875, instance876, instance877, instance878, instance879, instance880, instance881, instance882, instance883, instance884, instance885, instance886, instance887, instance888, instance889, instance890, instance891, instance892, instance893, instance894, instance895, instance896, instance897, instance898, instance899, instance900, instance901, instance902, instance903, instance904, instance905, instance906, instance907, instance908, instance909, instance910, instance911, instance912, instance913, instance914, instance915, instance916, instance917, instance918, instance919, instance920, instance921, instance922, instance923, instance924, instance925, instance926, instance927, instance928, instance929, instance930, instance931, instance932, instance933, instance934, instance935, instance936, instance937, instance938, instance939, instance940, instance941, instance942, instance943, instance944, instance945, instance946, instance947, instance948, instance949, instance950, instance951, instance952, instance953, instance954, instance955, instance956, instance957, instance958, instance959, instance960, instance961, instance962, instance963, instance964, instance965, instance966, instance967, instance968, instance969, instance970, instance971, instance972, instance973, instance974, instance975, instance976, instance977, instance978, instance979, instance980, instance981, instance982, instance983, instance984, instance985, instance986, instance987, instance988, instance989, instance990, instance991, instance992, instance993, instance994, instance995, instance996, instance997, instance998, instance999) + } +} + diff --git a/tests/pos/i19907/slow_100_3.scala b/tests/pos/i19907/slow_100_3.scala new file mode 100644 index 000000000000..a723ea8e4623 --- /dev/null +++ b/tests/pos/i19907/slow_100_3.scala @@ -0,0 +1,124 @@ + + +abstract class ServerEndpoint[-R, F[_]] { + type T0 + type T1 + type T2 +} +object ServerEndpoint { + type Full[_T0, _T1, _T2, -R, F[_]] = + ServerEndpoint[R, F] { + type T0 = _T0 + type T1 = _T1 + type T2 = _T2 + } + def apply[_T0, _T1, _T2, R, F[_]]: ServerEndpoint.Full[_T0, _T1, _T2, R, F] = ??? +} + +object Test { + type Route = ServerEndpoint[Any, Option] + def routes: List[ServerEndpoint[Any, Option]] = { + val instance0 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance1 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance2 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance3 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance4 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance5 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance6 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance7 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance8 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance9 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance10 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance11 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance12 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance13 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance14 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance15 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance16 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance17 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance18 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance19 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance20 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance21 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance22 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance23 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance24 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance25 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance26 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance27 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance28 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance29 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance30 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance31 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance32 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance33 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance34 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance35 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance36 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance37 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance38 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance39 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance40 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance41 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance42 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance43 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance44 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance45 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance46 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance47 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance48 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance49 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance50 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance51 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance52 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance53 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance54 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance55 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance56 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance57 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance58 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance59 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance60 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance61 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance62 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance63 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance64 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance65 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance66 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance67 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance68 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance69 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance70 = ServerEndpoint[Unit, Unit, Int, Any, Option] + val instance71 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance72 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance73 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance74 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance75 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance76 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance77 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance78 = ServerEndpoint[Unit, Unit, Unit, Any, Option] + val instance79 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance80 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance81 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance82 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance83 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance84 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance85 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance86 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance87 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance88 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance89 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance90 = ServerEndpoint[Int, Int, Unit, Any, Option] + val instance91 = ServerEndpoint[Unit, Int, Int, Any, Option] + val instance92 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance93 = ServerEndpoint[Unit, Int, Unit, Any, Option] + val instance94 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance95 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance96 = ServerEndpoint[Int, Unit, Int, Any, Option] + val instance97 = ServerEndpoint[Int, Int, Int, Any, Option] + val instance98 = ServerEndpoint[Int, Unit, Unit, Any, Option] + val instance99 = ServerEndpoint[Unit, Int, Unit, Any, Option] + List(instance0, instance1, instance2, instance3, instance4, instance5, instance6, instance7, instance8, instance9, instance10, instance11, instance12, instance13, instance14, instance15, instance16, instance17, instance18, instance19, instance20, instance21, instance22, instance23, instance24, instance25, instance26, instance27, instance28, instance29, instance30, instance31, instance32, instance33, instance34, instance35, instance36, instance37, instance38, instance39, instance40, instance41, instance42, instance43, instance44, instance45, instance46, instance47, instance48, instance49, instance50, instance51, instance52, instance53, instance54, instance55, instance56, instance57, instance58, instance59, instance60, instance61, instance62, instance63, instance64, instance65, instance66, instance67, instance68, instance69, instance70, instance71, instance72, instance73, instance74, instance75, instance76, instance77, instance78, instance79, instance80, instance81, instance82, instance83, instance84, instance85, instance86, instance87, instance88, instance89, instance90, instance91, instance92, instance93, instance94, instance95, instance96, instance97, instance98, instance99) + } +} + From 370c418f5482235506c80f29d3a4c6b6501c3dfc Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Tue, 1 Apr 2025 16:10:54 +0200 Subject: [PATCH 002/505] Skip widenSingletons in widenInferred if the inferred type is too large [Cherry-picked 7aef4159fab30bd7d1fd7f4e9180fbf55cd9b1f3][modified] From 6ef1e8d5e99bcfa6792d29de788339e4c8fff544 Mon Sep 17 00:00:00 2001 From: noti0na1 <8036790+noti0na1@users.noreply.github.com> Date: Wed, 20 Mar 2024 23:02:56 +0000 Subject: [PATCH 003/505] Make individual tests [Cherry-picked c5c94f0a5c0be43c6c79edca2f853bdf4e0e4ec1] --- tests/pos/{i19907/slow_1000_3.scala => i19907_slow_1000_3.scala} | 0 tests/pos/{i19907/slow_1000_4.scala => i19907_slow_1000_4.scala} | 0 tests/pos/{i19907/slow_100_3.scala => i19907_slow_100_3.scala} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename tests/pos/{i19907/slow_1000_3.scala => i19907_slow_1000_3.scala} (100%) rename tests/pos/{i19907/slow_1000_4.scala => i19907_slow_1000_4.scala} (100%) rename tests/pos/{i19907/slow_100_3.scala => i19907_slow_100_3.scala} (100%) diff --git a/tests/pos/i19907/slow_1000_3.scala b/tests/pos/i19907_slow_1000_3.scala similarity index 100% rename from tests/pos/i19907/slow_1000_3.scala rename to tests/pos/i19907_slow_1000_3.scala diff --git a/tests/pos/i19907/slow_1000_4.scala b/tests/pos/i19907_slow_1000_4.scala similarity index 100% rename from tests/pos/i19907/slow_1000_4.scala rename to tests/pos/i19907_slow_1000_4.scala diff --git a/tests/pos/i19907/slow_100_3.scala b/tests/pos/i19907_slow_100_3.scala similarity index 100% rename from tests/pos/i19907/slow_100_3.scala rename to tests/pos/i19907_slow_100_3.scala From 613e6e52a930cf3259ec7dd6b0cea8a41f91d877 Mon Sep 17 00:00:00 2001 From: odersky Date: Fri, 22 Mar 2024 18:00:59 +0100 Subject: [PATCH 004/505] Alternative scheme that does not require a size limit --- .../tools/dotc/core/ConstraintHandling.scala | 42 +++++++------------ .../dotty/tools/dotc/core/TypeComparer.scala | 2 +- .../src/dotty/tools/dotc/core/Types.scala | 24 ++++++----- 3 files changed, 29 insertions(+), 39 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala index df20505e65ce..e05cb61feef8 100644 --- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -657,27 +657,23 @@ trait ConstraintHandling { * as those could leak the annotation to users (see run/inferred-repeated-result). */ def widenInferred(inst: Type, bound: Type, widenUnions: Boolean)(using Context): Type = - def typeSize(tp: Type): Int = tp match - case tp: AndOrType => typeSize(tp.tp1) + typeSize(tp.tp2) - case _ => 1 - def widenOr(tp: Type) = if widenUnions then - val tpw = tp.widenUnion - if tpw ne tp then - if tpw.isTransparent() then - // Now also widen singletons of soft unions. Before these were skipped - // since we widenUnion on soft unions is independent of whether singletons - // are widened or not. This avoids an expensive subtype check in widenSingle, - // see 19907_*.scala for test cases. - tp.widenSingletons() - else if tpw <:< bound then tpw - else tp - else tp - else tp.hardenUnions + val tpw = tp.widenUnion + if tpw ne tp then + if tpw.isTransparent() then + // Now also widen singletons of soft unions. Before these were skipped + // since we widenUnion on soft unions is independent of whether singletons + // are widened or not. This avoids an expensive subtype check in widenSingle, + // see 19907_*.scala for test cases. + tp.widenSingletons() + else if tpw <:< bound then tpw + else tp + else tp + else tp.hardenUnions def widenSingle(tp: Type) = - val tpw = tp.widenSingletons + val tpw = tp.widenSingletons(skipSoftUnions = widenUnions) if (tpw ne tp) && (tpw <:< bound) then tpw else tp def isSingleton(tp: Type): Boolean = tp match @@ -687,16 +683,8 @@ trait ConstraintHandling { val wideInst = if isSingleton(bound) then inst else - val widenedFromUnion = - if widenUnions && typeSize(inst) > 64 then - // If the inferred type `inst` is too large, the subtype check for `bound` in `widenSingle` - // can be expensive due to comparisons between large union types, so we avoid it by - // `widenUnion` directly here. - // See issue #19907. - widenOr(inst) - else - val widenedFromSingle = widenSingle(inst) - if widenUnions then widenOr(widenedFromSingle) else widenedFromSingle.hardenUnions + val widenedFromSingle = widenSingle(inst) + val widenedFromUnion = widenOr(widenedFromSingle) val widened = dropTransparentTraits(widenedFromUnion, bound) widenIrreducible(widened) diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index c69ea177ee96..5e0d9a98aa74 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -479,7 +479,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling def widenOK = (tp2.widenSingletons eq tp2) && (tp1.widenSingletons ne tp1) - && inFrozenGadtAndConstraint(recur(tp1.widenSingletons, tp2)) + && inFrozenGadtAndConstraint(recur(tp1.widenSingletons(), tp2)) def joinOK = tp2.dealiasKeepRefiningAnnots match { case tp2: AppliedType if !tp2.tycon.typeSymbol.isClass => diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 6cfe58bae2ea..f60c609eadd1 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1365,15 +1365,15 @@ object Types extends TypeUtils { * and going to the operands of & and |. * Overridden and cached in OrType. */ - def widenSingletons(using Context): Type = dealias match { + def widenSingletons(skipSoftUnions: Boolean = false)(using Context): Type = dealias match { case tp: SingletonType => tp.widen case tp: OrType => - val tp1w = tp.widenSingletons + val tp1w = tp.widenSingletons(skipSoftUnions) if (tp1w eq tp) this else tp1w case tp: AndType => - val tp1w = tp.tp1.widenSingletons - val tp2w = tp.tp2.widenSingletons + val tp1w = tp.tp1.widenSingletons(skipSoftUnions) + val tp2w = tp.tp2.widenSingletons(skipSoftUnions) if ((tp.tp1 eq tp1w) && (tp.tp2 eq tp2w)) this else tp1w & tp2w case _ => this @@ -3532,8 +3532,8 @@ object Types extends TypeUtils { else tp1.atoms | tp2.atoms private def computeWidenSingletons()(using Context): Type = - val tp1w = tp1.widenSingletons - val tp2w = tp2.widenSingletons + val tp1w = tp1.widenSingletons() + val tp2w = tp2.widenSingletons() if ((tp1 eq tp1w) && (tp2 eq tp2w)) this else TypeComparer.lub(tp1w, tp2w, isSoft = isSoft) override def atoms(using Context): Atoms = @@ -3542,11 +3542,13 @@ object Types extends TypeUtils { if !isProvisional then atomsRunId = ctx.runId myAtoms - override def widenSingletons(using Context): Type = - if widenedRunId != ctx.runId then - myWidened = computeWidenSingletons() - if !isProvisional then widenedRunId = ctx.runId - myWidened + override def widenSingletons(skipSoftUnions: Boolean)(using Context): Type = + if isSoft && skipSoftUnions then this + else + if widenedRunId != ctx.runId then + myWidened = computeWidenSingletons() + if !isProvisional then widenedRunId = ctx.runId + myWidened def derivedOrType(tp1: Type, tp2: Type, soft: Boolean = isSoft)(using Context): Type = if ((tp1 eq this.tp1) && (tp2 eq this.tp2) && soft == isSoft) this From 9a08f21683596f23fd2a0ed083a73f59bcc5f511 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Tue, 1 Apr 2025 16:17:49 +0200 Subject: [PATCH 005/505] Alternative scheme that does not require a size limit [Cherry-picked 612ba920474b44fefa26821412a5b7f0efe0bbcd][modified] From 2ea9d6e3a78b4775c29b0b421a426784edc9fec2 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Mon, 25 Mar 2024 16:17:59 +0100 Subject: [PATCH 006/505] Refine logic for widenSingle [Cherry-picked fd61afbd1a403ca9093d871d8a1ca0d83f3d2ce1] --- .../dotty/tools/dotc/core/ConstraintHandling.scala | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala index e05cb61feef8..617104630850 100644 --- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -663,17 +663,17 @@ trait ConstraintHandling { if tpw ne tp then if tpw.isTransparent() then // Now also widen singletons of soft unions. Before these were skipped - // since we widenUnion on soft unions is independent of whether singletons + // since widenUnion on soft unions is independent of whether singletons // are widened or not. This avoids an expensive subtype check in widenSingle, - // see 19907_*.scala for test cases. - tp.widenSingletons() + // see i19907_*.scala for test cases. + widenSingle(tp, skipSoftUnions = false) else if tpw <:< bound then tpw else tp else tp else tp.hardenUnions - def widenSingle(tp: Type) = - val tpw = tp.widenSingletons(skipSoftUnions = widenUnions) + def widenSingle(tp: Type, skipSoftUnions: Boolean) = + val tpw = tp.widenSingletons(skipSoftUnions) if (tpw ne tp) && (tpw <:< bound) then tpw else tp def isSingleton(tp: Type): Boolean = tp match @@ -683,7 +683,7 @@ trait ConstraintHandling { val wideInst = if isSingleton(bound) then inst else - val widenedFromSingle = widenSingle(inst) + val widenedFromSingle = widenSingle(inst, skipSoftUnions = widenUnions) val widenedFromUnion = widenOr(widenedFromSingle) val widened = dropTransparentTraits(widenedFromUnion, bound) widenIrreducible(widened) From 579278bbd5480afe9be7b9b2a02450ac62d8983f Mon Sep 17 00:00:00 2001 From: Katarzyna Marek Date: Wed, 15 Jan 2025 13:23:56 +0100 Subject: [PATCH 007/505] fix: hover and go to definition for named tuples (#22202) resolves: https://github.com/scala/scala3/issues/20500 [Cherry-picked 6a1714b84547e7074343550c57aa2a8825f9018b] --- .../main/dotty/tools/pc/HoverProvider.scala | 51 +++++++++++++----- .../dotty/tools/pc/MetalsInteractive.scala | 54 ++++++++++++------- .../dotty/tools/pc/PcDefinitionProvider.scala | 2 +- .../tests/definition/PcDefinitionSuite.scala | 9 ++++ .../tools/pc/tests/hover/HoverTermSuite.scala | 30 +++++++++++ 5 files changed, 113 insertions(+), 33 deletions(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/HoverProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/HoverProvider.scala index a667b038c894..769eaf024862 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/HoverProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/HoverProvider.scala @@ -104,10 +104,10 @@ object HoverProvider: ) match case Nil => fallbackToDynamics(path, printer, contentType) - case (symbol, tpe) :: _ + case (symbol, tpe, _) :: _ if symbol.name == nme.selectDynamic || symbol.name == nme.applyDynamic => fallbackToDynamics(path, printer, contentType) - case symbolTpes @ ((symbol, tpe) :: _) => + case symbolTpes @ ((symbol, tpe, None) :: _) => val exprTpw = tpe.widenTermRefExpr.deepDealias val hoverString = tpw match @@ -153,6 +153,21 @@ object HoverProvider: case _ => ju.Optional.empty().nn end match + case (_, tpe, Some(namedTupleArg)) :: _ => + val exprTpw = tpe.widenTermRefExpr.deepDealias + printer.expressionType(exprTpw) match + case Some(tpe) => + ju.Optional.of( + new ScalaHover( + expressionType = Some(tpe), + symbolSignature = Some(s"$namedTupleArg: $tpe"), + docstring = None, + forceExpressionType = false, + contextInfo = printer.getUsedRenamesInfo, + contentType = contentType + ) + ).nn + case _ => ju.Optional.empty().nn end match end if end hover @@ -165,23 +180,31 @@ object HoverProvider: printer: ShortenedTypePrinter, contentType: ContentType )(using Context): ju.Optional[HoverSignature] = path match - case SelectDynamicExtractor(sel, n, name) => + case SelectDynamicExtractor(sel, n, name, rest) => def findRefinement(tp: Type): Option[HoverSignature] = tp match - case RefinedType(_, refName, tpe) if name == refName.toString() => + case RefinedType(_, refName, tpe) if (name == refName.toString() || refName.toString() == nme.Fields.toString()) => + val resultType = + rest match + case Select(_, asInstanceOf) :: TypeApply(_, List(tpe)) :: _ if asInstanceOf == nme.asInstanceOfPM => + tpe.tpe.widenTermRefExpr.deepDealias + case _ if n == nme.selectDynamic => tpe.resultType + case _ => tpe + val tpeString = - if n == nme.selectDynamic then s": ${printer.tpe(tpe.resultType)}" - else printer.tpe(tpe) + if n == nme.selectDynamic then s": ${printer.tpe(resultType)}" + else printer.tpe(resultType) val valOrDef = - if n == nme.selectDynamic && !tpe.isInstanceOf[ExprType] - then "val" - else "def" + if refName.toString() == nme.Fields.toString() then "" + else if n == nme.selectDynamic && !tpe.isInstanceOf[ExprType] + then "val " + else "def " Some( new ScalaHover( expressionType = Some(tpeString), - symbolSignature = Some(s"$valOrDef $name$tpeString"), + symbolSignature = Some(s"$valOrDef$name$tpeString"), contextInfo = printer.getUsedRenamesInfo, contentType = contentType ) @@ -208,16 +231,16 @@ object SelectDynamicExtractor: case Select(_, _) :: Apply( Select(Apply(reflSel, List(sel)), n), List(Literal(Constant(name: String))) - ) :: _ + ) :: rest if (n == nme.selectDynamic || n == nme.applyDynamic) && nme.reflectiveSelectable == reflSel.symbol.name => - Some(sel, n, name) + Some(sel, n, name, rest) // tests `selectable`, `selectable2` and `selectable-full` in HoverScala3TypeSuite case Select(_, _) :: Apply( Select(sel, n), List(Literal(Constant(name: String))) - ) :: _ if n == nme.selectDynamic || n == nme.applyDynamic => - Some(sel, n, name) + ) :: rest if n == nme.selectDynamic || n == nme.applyDynamic => + Some(sel, n, name, rest) case _ => None end match end unapply diff --git a/presentation-compiler/src/main/dotty/tools/pc/MetalsInteractive.scala b/presentation-compiler/src/main/dotty/tools/pc/MetalsInteractive.scala index 0e978049d177..a24ed5c7c9e7 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/MetalsInteractive.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/MetalsInteractive.scala @@ -5,12 +5,16 @@ import scala.annotation.tailrec import dotc.* import ast.*, tpd.* +import dotty.tools.dotc.core.Constants.* import core.*, Contexts.*, Flags.*, Names.*, Symbols.*, Types.* +import dotty.tools.dotc.core.StdNames.* import interactive.* import util.* import util.SourcePosition +import dotty.tools.pc.utils.InteractiveEnrichments.* object MetalsInteractive: + type NamedTupleArg = String def contextOfStat( stats: List[Tree], @@ -110,7 +114,7 @@ object MetalsInteractive: pos: SourcePosition, indexed: IndexedContext, skipCheckOnName: Boolean = false - ): List[(Symbol, Type)] = + ): List[(Symbol, Type, Option[String])] = import indexed.ctx path match // For a named arg, find the target `DefDef` and jump to the param @@ -118,59 +122,59 @@ object MetalsInteractive: val funSym = fn.symbol if funSym.is(Synthetic) && funSym.owner.is(CaseClass) then val sym = funSym.owner.info.member(name).symbol - List((sym, sym.info)) + List((sym, sym.info, None)) else val paramSymbol = for param <- funSym.paramSymss.flatten.find(_.name == name) yield param val sym = paramSymbol.getOrElse(fn.symbol) - List((sym, sym.info)) + List((sym, sym.info, None)) case (_: untpd.ImportSelector) :: (imp: Import) :: _ => importedSymbols(imp, _.span.contains(pos.span)).map(sym => - (sym, sym.info) + (sym, sym.info, None) ) case (imp: Import) :: _ => importedSymbols(imp, _.span.contains(pos.span)).map(sym => - (sym, sym.info) + (sym, sym.info, None) ) // wildcard param case head :: _ if (head.symbol.is(Param) && head.symbol.is(Synthetic)) => - List((head.symbol, head.typeOpt)) + List((head.symbol, head.typeOpt, None)) case (head @ Select(target, name)) :: _ if head.symbol.is(Synthetic) && name == StdNames.nme.apply => val sym = target.symbol if sym.is(Synthetic) && sym.is(Module) then - List((sym.companionClass, sym.companionClass.info)) - else List((target.symbol, target.typeOpt)) + List((sym.companionClass, sym.companionClass.info, None)) + else List((target.symbol, target.typeOpt, None)) // L@@ft(...) case (head @ ApplySelect(select)) :: _ if select.qualifier.sourcePos.contains(pos) && select.name == StdNames.nme.apply => - List((head.symbol, head.typeOpt)) + List((head.symbol, head.typeOpt, None)) // for Inlined we don't have a symbol, but it's needed to show proper type case (head @ Inlined(call, bindings, expansion)) :: _ => - List((call.symbol, head.typeOpt)) + List((call.symbol, head.typeOpt, None)) // for comprehension case (head @ ApplySelect(select)) :: _ if isForSynthetic(head) => // If the cursor is on the qualifier, return the symbol for it // `for { x <- List(1).head@@Option }` returns the symbol of `headOption` if select.qualifier.sourcePos.contains(pos) then - List((select.qualifier.symbol, select.qualifier.typeOpt)) + List((select.qualifier.symbol, select.qualifier.typeOpt, None)) // Otherwise, returns the symbol of for synthetics such as "withFilter" - else List((head.symbol, head.typeOpt)) + else List((head.symbol, head.typeOpt, None)) // f@@oo.bar case Select(target, _) :: _ if target.span.isSourceDerived && target.sourcePos.contains(pos) => - List((target.symbol, target.typeOpt)) + List((target.symbol, target.typeOpt, None)) /* In some cases type might be represented by TypeTree, however it's possible * that the type tree will not be marked properly as synthetic even if it doesn't @@ -185,7 +189,7 @@ object MetalsInteractive: */ case (tpt: TypeTree) :: parent :: _ if tpt.span != parent.span && !tpt.symbol.is(Synthetic) => - List((tpt.symbol, tpt.typeOpt)) + List((tpt.symbol, tpt.typeOpt, None)) /* TypeTest class https://dotty.epfl.ch/docs/reference/other-new-features/type-test.html * compiler automatically adds unapply if possible, we need to find the type symbol @@ -195,14 +199,28 @@ object MetalsInteractive: pat match case UnApply(fun, _, pats) => val tpeSym = pats.head.typeOpt.typeSymbol - List((tpeSym, tpeSym.info)) + List((tpeSym, tpeSym.info, None)) case _ => Nil + // Handle select on named tuples + case (Apply(Apply(TypeApply(fun, List(t1, t2)), List(ddef)), List(Literal(Constant(i: Int))))) :: _ + if fun.symbol.exists && fun.symbol.name == nme.apply && + fun.symbol.owner.exists && fun.symbol.owner == getModuleIfDefined("scala.NamedTuple").moduleClass => + def getIndex(t: Tree): Option[Type] = + t.tpe.dealias match + case AppliedType(_, args) => args.get(i) + case _ => None + val name = getIndex(t1) match + case Some(c: ConstantType) => c.value.stringValue + case _ => "" + val tpe = getIndex(t2).getOrElse(NoType) + List((ddef.symbol, tpe, Some(name))) + case path @ head :: tail => if head.symbol.is(Exported) then val sym = head.symbol.sourceSymbol - List((sym, sym.info)) + List((sym, sym.info, None)) else if head.symbol.is(Synthetic) then enclosingSymbolsWithExpressionType( tail, @@ -217,7 +235,7 @@ object MetalsInteractive: pos, indexed.ctx.source ) - then List((head.symbol, head.typeOpt)) + then List((head.symbol, head.typeOpt, None)) /* Type tree for List(1) has an Int type variable, which has span * but doesn't exist in code. * https://github.com/lampepfl/dotty/issues/15937 @@ -234,7 +252,7 @@ object MetalsInteractive: indexed, skipCheckOnName ) - else recovered.map(sym => (sym, sym.info)) + else recovered.map(sym => (sym, sym.info, None)) end if case Nil => Nil end match diff --git a/presentation-compiler/src/main/dotty/tools/pc/PcDefinitionProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/PcDefinitionProvider.scala index 3b2284bef1d0..7d8e4dfad081 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/PcDefinitionProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/PcDefinitionProvider.scala @@ -101,7 +101,7 @@ class PcDefinitionProvider( val enclosing = path.expandRangeToEnclosingApply(pos) val typeSymbols = MetalsInteractive .enclosingSymbolsWithExpressionType(enclosing, pos, indexed) - .map { case (_, tpe) => + .map { case (_, tpe, _) => tpe.typeSymbol } typeSymbols match diff --git a/presentation-compiler/test/dotty/tools/pc/tests/definition/PcDefinitionSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/definition/PcDefinitionSuite.scala index fab21ffdee0a..ff4c6ec25e27 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/definition/PcDefinitionSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/definition/PcDefinitionSuite.scala @@ -504,3 +504,12 @@ class PcDefinitionSuite extends BasePcDefinitionSuite: |val a = MyIntOut(1).un@@even |""".stripMargin, ) + + @Test def `named-tuples` = + check( + """|import scala.language.experimental.namedTuples + | + |val <> = (name = "Bob", age = 42, height = 1.9d) + |val foo_name = foo.na@@me + |""".stripMargin + ) diff --git a/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTermSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTermSuite.scala index 2828b946c7c3..5e20045babfb 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTermSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTermSuite.scala @@ -717,3 +717,33 @@ class HoverTermSuite extends BaseHoverSuite: |""".stripMargin, """def ???: Nothing""".stripMargin.hover ) + + @Test def `named-tuples`: Unit = + check( + """import scala.language.experimental.namedTuples + | + |val foo = (name = "Bob", age = 42, height = 1.9d) + |val foo_name = foo.na@@me + |""".stripMargin, + "name: String".hover + ) + + @Test def `named-tuples2`: Unit = + check( + """|import scala.language.experimental.namedTuples + | + |import NamedTuple.* + | + |class NamedTupleSelectable extends Selectable { + | type Fields <: AnyNamedTuple + | def selectDynamic(name: String): Any = ??? + |} + | + |val person = new NamedTupleSelectable { + | type Fields = (name: String, city: String) + |} + | + |val person_name = person.na@@me + |""".stripMargin, + "name: String".hover + ) From c83d67c5802e0fd0cf277f1ca4a060756d7cedf8 Mon Sep 17 00:00:00 2001 From: Matt Bovel Date: Tue, 14 Jan 2025 15:50:04 +0000 Subject: [PATCH 008/505] Preserve hard unions in widenSingletons [Cherry-picked 2472a58b4d7ae99f4992bb5d1a1b4d4b77d04528] --- .../src/dotty/tools/dotc/core/Types.scala | 8 ++++---- tests/pos/22219.scala | 5 +++++ tests/pos/22219b.scala | 20 +++++++++++++++++++ 3 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 tests/pos/22219.scala create mode 100644 tests/pos/22219b.scala diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index f60c609eadd1..5fe6c3174c04 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1361,9 +1361,9 @@ object Types extends TypeUtils { case tp => tp - /** Widen all top-level singletons reachable by dealiasing - * and going to the operands of & and |. - * Overridden and cached in OrType. + /** Widen all top-level singletons reachable by dealiasing and going to the + * operands of intersections and soft unions (only when `skipSoftUnions` is + * `false`). Overridden and cached in [[OrType]]. */ def widenSingletons(skipSoftUnions: Boolean = false)(using Context): Type = dealias match { case tp: SingletonType => @@ -3543,7 +3543,7 @@ object Types extends TypeUtils { myAtoms override def widenSingletons(skipSoftUnions: Boolean)(using Context): Type = - if isSoft && skipSoftUnions then this + if !isSoft || skipSoftUnions then this else if widenedRunId != ctx.runId then myWidened = computeWidenSingletons() diff --git a/tests/pos/22219.scala b/tests/pos/22219.scala new file mode 100644 index 000000000000..fd455d5dc902 --- /dev/null +++ b/tests/pos/22219.scala @@ -0,0 +1,5 @@ +type MonthNumber = 1 | 2 + +def main = + val x = 1: MonthNumber + val y: MonthNumber = x diff --git a/tests/pos/22219b.scala b/tests/pos/22219b.scala new file mode 100644 index 000000000000..8046ef802845 --- /dev/null +++ b/tests/pos/22219b.scala @@ -0,0 +1,20 @@ +type MonthNumber = + 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 + +def main = + List[(String, MonthNumber)]( + "January" -> 1, + "February" -> 2, + "March" -> 3, + "April" -> 4, + "May" -> 5, + "June"-> 6, + "July" -> 7, + "August" -> 8, + "September" -> 9, + "October" -> 10, + "November" -> 11, + "December" -> 12 + ).foreach { (name, number) => + summon[number.type <:< MonthNumber] + } From bb623f1e232a7de63cb893fa8c6f07483d15516f Mon Sep 17 00:00:00 2001 From: Yichen Xu Date: Mon, 13 Jan 2025 20:46:01 +0800 Subject: [PATCH 009/505] Improve the usage of inclusive language Changes: - blacklist -> excludelist - whitelist -> allowlist Discussion: - https://github.com/scala/scala3/issues/21988 - https://github.com/scala/scala3/pull/22360#issuecomment-2587398739 --- .../src/dotty/tools/dotc/core/Contexts.scala | 2 +- .../src/dotty/tools/dotc/core/Names.scala | 2 +- .../dotc/core/classfile/ClassfileParser.scala | 4 +- .../dotc/neg-best-effort-pickling.excludelist | 23 +++ .../neg-best-effort-unpickling.excludelist | 17 +++ ...it-global-scala2-library-tasty.excludelist | 21 +++ .../dotc/neg-scala2-library-tasty.excludelist | 2 + ...austivity-scala2-library-tasty.excludelist | 4 + ...y.blacklist => pos-from-tasty.excludelist} | 0 ...it-global-scala2-library-tasty.excludelist | 5 + .../test/dotc/pos-test-pickling.excludelist | 143 ++++++++++++++++++ ...y.blacklist => run-from-tasty.excludelist} | 0 ...un-macros-scala2-library-tasty.excludelist | 5 + .../test/dotc/run-test-pickling.excludelist | 52 +++++++ compiler/test/dotty/tools/TestSources.scala | 17 +-- .../dotty/tools/dotc/CompilationTests.scala | 4 +- .../dotty/tools/dotc/FromTastyTests.scala | 4 +- .../tools/dotc/parsing/ScannerTest.scala | 10 +- .../test/dotty/tools/vulpix/FileFilter.scala | 8 +- .../dotty/tools/vulpix/ParallelTesting.scala | 2 +- project/Build.scala | 2 +- .../tools/scaladoc/tasty/BasicSupport.scala | 4 +- 22 files changed, 301 insertions(+), 30 deletions(-) create mode 100644 compiler/test/dotc/neg-best-effort-pickling.excludelist create mode 100644 compiler/test/dotc/neg-best-effort-unpickling.excludelist create mode 100644 compiler/test/dotc/neg-init-global-scala2-library-tasty.excludelist create mode 100644 compiler/test/dotc/neg-scala2-library-tasty.excludelist create mode 100644 compiler/test/dotc/patmat-exhaustivity-scala2-library-tasty.excludelist rename compiler/test/dotc/{pos-from-tasty.blacklist => pos-from-tasty.excludelist} (100%) create mode 100644 compiler/test/dotc/pos-init-global-scala2-library-tasty.excludelist create mode 100644 compiler/test/dotc/pos-test-pickling.excludelist rename compiler/test/dotc/{run-from-tasty.blacklist => run-from-tasty.excludelist} (100%) create mode 100644 compiler/test/dotc/run-macros-scala2-library-tasty.excludelist create mode 100644 compiler/test/dotc/run-test-pickling.excludelist diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index bde23de135e4..8c09a3f24fa0 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -121,7 +121,7 @@ object Contexts { * risk of capturing complete trees. * - To make sure these rules are kept, it would be good to do a sanity * check using bytecode inspection with javap or scalap: Keep track - * of all class fields of type context; allow them only in whitelisted + * of all class fields of type context; allow them only in allowlisted * classes (which should be short-lived). */ abstract class Context(val base: ContextBase) { thiscontext => diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 3f9667b08067..a31ab0662ee4 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -401,7 +401,7 @@ object Names { } /** It's OK to take a toString if the stacktrace does not contain a method - * from GenBCode or it also contains one of the whitelisted methods below. + * from GenBCode or it also contains one of the allowed methods below. */ private def toStringOK = { val trace: Array[StackTraceElement] = Thread.currentThread.nn.getStackTrace.asInstanceOf[Array[StackTraceElement]] diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index c20b6c73b1ea..37367ca56488 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -904,7 +904,7 @@ class ClassfileParser( // Nothing$ and Null$ were incorrectly emitted with a Scala attribute // instead of ScalaSignature before 2.13.0-M2, see https://github.com/scala/scala/pull/5952 - private val scalaUnpickleWhitelist = List(tpnme.nothingClass, tpnme.nullClass) + private val scalaUnpickleAllowlist = List(tpnme.nothingClass, tpnme.nullClass) /** Parse inner classes. Expects `in.bp` to point to the superclass entry. * Restores the old `bp`. @@ -1028,7 +1028,7 @@ class ClassfileParser( report.error(s"Found a TASTY attribute with a length different from 16 in $classfile. This is likely a bug in the compiler. Please report.", NoSourcePosition) } - if scan(tpnme.ScalaATTR) && !scalaUnpickleWhitelist.contains(classRoot.name) + if scan(tpnme.ScalaATTR) && !scalaUnpickleAllowlist.contains(classRoot.name) && !(classRoot.name.startsWith("Tuple") && classRoot.name.endsWith("$sp")) && !(classRoot.name.startsWith("Product") && classRoot.name.endsWith("$sp")) then diff --git a/compiler/test/dotc/neg-best-effort-pickling.excludelist b/compiler/test/dotc/neg-best-effort-pickling.excludelist new file mode 100644 index 000000000000..99a83a467f08 --- /dev/null +++ b/compiler/test/dotc/neg-best-effort-pickling.excludelist @@ -0,0 +1,23 @@ +export-in-extension.scala +i12456.scala +i8623.scala +i1642.scala +i16696.scala +constructor-proxy-values.scala +i9328.scala +i15414.scala +i6796.scala +i14013.scala +toplevel-cyclic +curried-dependent-ift.scala +i17121.scala +illegal-match-types.scala +i13780-1.scala +i20317a.scala +i11226.scala +i974.scala +i13864.scala + +# semantic db generation fails in the first compilation +i1642.scala +i15158.scala diff --git a/compiler/test/dotc/neg-best-effort-unpickling.excludelist b/compiler/test/dotc/neg-best-effort-unpickling.excludelist new file mode 100644 index 000000000000..1e22d919f25a --- /dev/null +++ b/compiler/test/dotc/neg-best-effort-unpickling.excludelist @@ -0,0 +1,17 @@ +# cyclic reference crashes +i4368.scala +i827.scala +cycles.scala +i5332.scala +i4369c.scala +i1806.scala +i0091-infpaths.scala +exports.scala +i14834.scala + +# other type related crashes +i4653.scala +overrideClass.scala + +# repeating on a top level type definition +i18750.scala diff --git a/compiler/test/dotc/neg-init-global-scala2-library-tasty.excludelist b/compiler/test/dotc/neg-init-global-scala2-library-tasty.excludelist new file mode 100644 index 000000000000..03b020db64d9 --- /dev/null +++ b/compiler/test/dotc/neg-init-global-scala2-library-tasty.excludelist @@ -0,0 +1,21 @@ +## See #18882 +patmat.scala +t9312.scala +unapplySeq-implicit-arg.scala +unapplySeq-implicit-arg2.scala +unapplySeq-implicit-arg3.scala +ScalaCheck.scala +mutable-read8.scala +TypeCast.scala +global-cycle8.scala +global-cycle6.scala +i12544b.scala +t9360.scala +mutable-array.scala +patmat-unapplySeq2.scala +line-spacing.scala +global-list.scala +t5366.scala +mutable-read7.scala +t9115.scala +Color.scala \ No newline at end of file diff --git a/compiler/test/dotc/neg-scala2-library-tasty.excludelist b/compiler/test/dotc/neg-scala2-library-tasty.excludelist new file mode 100644 index 000000000000..d46a021ddd50 --- /dev/null +++ b/compiler/test/dotc/neg-scala2-library-tasty.excludelist @@ -0,0 +1,2 @@ +i8752.scala +f-interpolator-neg.scala # Additional: A pure expression does nothing in statement position diff --git a/compiler/test/dotc/patmat-exhaustivity-scala2-library-tasty.excludelist b/compiler/test/dotc/patmat-exhaustivity-scala2-library-tasty.excludelist new file mode 100644 index 000000000000..6f1717d532fd --- /dev/null +++ b/compiler/test/dotc/patmat-exhaustivity-scala2-library-tasty.excludelist @@ -0,0 +1,4 @@ +t7746.scala # order of exhaustivity suggestions differs +t4408.scala # order of exhaustivity suggestions differs +patmat-ortype.scala # order of exhaustivity suggestions differs +i13003.scala # order of exhaustivity suggestions differs diff --git a/compiler/test/dotc/pos-from-tasty.blacklist b/compiler/test/dotc/pos-from-tasty.excludelist similarity index 100% rename from compiler/test/dotc/pos-from-tasty.blacklist rename to compiler/test/dotc/pos-from-tasty.excludelist diff --git a/compiler/test/dotc/pos-init-global-scala2-library-tasty.excludelist b/compiler/test/dotc/pos-init-global-scala2-library-tasty.excludelist new file mode 100644 index 000000000000..eb60fc3b7c14 --- /dev/null +++ b/compiler/test/dotc/pos-init-global-scala2-library-tasty.excludelist @@ -0,0 +1,5 @@ +## See #18882 +patmat.scala +patmat-interpolator.scala +unapplySeq-implicit-arg-pos.scala +global-cycle11.scala diff --git a/compiler/test/dotc/pos-test-pickling.excludelist b/compiler/test/dotc/pos-test-pickling.excludelist new file mode 100644 index 000000000000..23c79affada0 --- /dev/null +++ b/compiler/test/dotc/pos-test-pickling.excludelist @@ -0,0 +1,143 @@ +i94-nada.scala +i1812.scala +i1867.scala +i3067.scala +t2712-5.scala +t284-pos.scala +t3249 +t3486 +t3612.scala +reference +scala-days-2019-slides +i7048e.scala +i8052.scala +tuple-filter.scala +i7740a.scala +i7740b.scala +i6507b.scala +i12299a.scala +i13871.scala +i15181.scala +i15922.scala +i15926.scala +t5031_2.scala +i16997.scala +i7414.scala +i17588.scala +i8300.scala +i9804.scala +i13433.scala +i16649-irrefutable.scala +strict-pattern-bindings-3.0-migration.scala +i17186b.scala +i11982a.scala +i17255 +i17735.scala + +# Tree is huge and blows stack for printing Text +i7034.scala + +# Causes cyclic reference by interacting with compiler stdlib types +stdlib + +# Stale symbol: package object scala +seqtype-cycle + +# type of super reference changes due to late addition of Mirror.Singleton +i939.scala +i13332super.scala + +# Match types +i7872.scala +i11236.scala +i11247.scala +i11250 +i9999.scala +8649.scala +12093.scala +9757.scala +9890.scala +13491.scala +7512.scala +i6505.scala +i15158.scala +i15155.scala +i15827.scala +i17149.scala +tuple-fold.scala +mt-redux-norm.perspective.scala +i18211.scala +10867.scala +named-tuples1.scala +i20897.scala +i20512.scala + +# Opaque type +i5720.scala + +# Tuples +toexproftuple.scala +i7580.scala + +# Nullability +nullable.scala + +# parameter untupling with overloaded functions (see comment in Applications.normArg) +i7757.scala + +# splice type tag dealiased in this reference +i8651b.scala + +# uneliminated @uncheckedVariance after pickling +annot-bootstrap.scala + +# interaction with Scala-2's implicitly +i9793.scala + +# lazy_implicit symbol has different position after pickling +i8182.scala + +# local lifted value in annotation argument has different position after pickling +i2797a + +# Late instantiation of type variable in tryInsertImplicitOnQualifier +# allows to simplify a type that was already computed +i13842.scala + +# Position change under captureChecking +boxmap-paper.scala + +# Function types print different after unpickling since test mispredicts Feature.preFundsEnabled +caps-universal.scala + +# GADT cast applied to singleton type difference +i4176-gadt.scala + +# GADT difference +i13974a.scala +i15867.scala + +java-inherited-type1 + +# recursion limit exceeded +i7445b.scala + +# more aggresive reduce projection makes a difference +i15525.scala +i19955a.scala +i19955b.scala +i20053b.scala + +# alias types at different levels of dereferencing +parsercombinators-givens.scala +parsercombinators-givens-2.scala +parsercombinators-ctx-bounds.scala +parsercombinators-this.scala +parsercombinators-arrow.scala +parsercombinators-new-syntax.scala +hylolib-deferred-given +hylolib-cb +hylolib + +# typecheckErrors method unpickling +i21415.scala diff --git a/compiler/test/dotc/run-from-tasty.blacklist b/compiler/test/dotc/run-from-tasty.excludelist similarity index 100% rename from compiler/test/dotc/run-from-tasty.blacklist rename to compiler/test/dotc/run-from-tasty.excludelist diff --git a/compiler/test/dotc/run-macros-scala2-library-tasty.excludelist b/compiler/test/dotc/run-macros-scala2-library-tasty.excludelist new file mode 100644 index 000000000000..6fdfccf7646c --- /dev/null +++ b/compiler/test/dotc/run-macros-scala2-library-tasty.excludelist @@ -0,0 +1,5 @@ +# Checkfile differences for equivalent type +tasty-extractors-1 +tasty-extractors-2 +tasty-extractors-types +type-print diff --git a/compiler/test/dotc/run-test-pickling.excludelist b/compiler/test/dotc/run-test-pickling.excludelist new file mode 100644 index 000000000000..c880a4b78f23 --- /dev/null +++ b/compiler/test/dotc/run-test-pickling.excludelist @@ -0,0 +1,52 @@ +## Many of these tests fail because CompilationTests.pickling does not handle +## tests containing java files correctly + +derive-generic.scala +eff-dependent.scala +enum-java +i5257.scala +i7212 +i7868.scala +i9011.scala +i9473.scala +i13433.scala +i13433b.scala +macros-in-same-project1 +mixin-forwarder-overload +t10889 +t3452d +t3452e +t3452g +t7374 +t8905 +tuple-drop.scala +tuple-ops.scala +tuple-ops.scala +tuple-take.scala +tuple-zip.scala +tuples1.scala +tuples1a.scala +tuples1b.scala +typeclass-derivation-doc-example.scala +typeclass-derivation1.scala +typeclass-derivation2.scala +typeclass-derivation2a.scala +typeclass-derivation2b.scala +typeclass-derivation2c.scala +typeclass-derivation2d.scala +typeclass-derivation3.scala +varargs-abstract +zero-arity-case-class.scala +i12194.scala +i12753 +t6138 +t6138-2 +i12656.scala +trait-static-forwarder +i17255 +named-tuples-strawman-2.scala + +# typecheckErrors method unpickling +typeCheckErrors.scala +i18150.scala + diff --git a/compiler/test/dotty/tools/TestSources.scala b/compiler/test/dotty/tools/TestSources.scala index 68a260de81e4..15cb0c741ede 100644 --- a/compiler/test/dotty/tools/TestSources.scala +++ b/compiler/test/dotty/tools/TestSources.scala @@ -11,28 +11,27 @@ object TestSources { // pos tests lists - def posFromTastyBlacklistFile: String = "compiler/test/dotc/pos-from-tasty.blacklist" - def posTestPicklingBlacklistFile: String = "compiler/test/dotc/pos-test-pickling.blacklist" + def posFromTastyExcludelistFile: String = "compiler/test/dotc/pos-from-tasty.excludelist" + def posTestPicklingExcludelistFile: String = "compiler/test/dotc/pos-test-pickling.excludelist" def posTestRecheckExcludesFile: String = "compiler/test/dotc/pos-test-recheck.excludes" def posLazyValsAllowlistFile: String = "compiler/test/dotc/pos-lazy-vals-tests.allowlist" def posLintingAllowlistFile: String = "compiler/test/dotc/pos-linting.allowlist" - def posFromTastyBlacklisted: List[String] = loadList(posFromTastyBlacklistFile) - def posTestPicklingBlacklisted: List[String] = loadList(posTestPicklingBlacklistFile) + def posFromTastyExcludelisted: List[String] = loadList(posFromTastyExcludelistFile) + def posTestPicklingExcludelisted: List[String] = loadList(posTestPicklingExcludelistFile) def posTestRecheckExcluded: List[String] = loadList(posTestRecheckExcludesFile) def posLazyValsAllowlist: List[String] = loadList(posLazyValsAllowlistFile) def posLintingAllowlist: List[String] = loadList(posLintingAllowlistFile) // run tests lists - def runFromTastyBlacklistFile: String = "compiler/test/dotc/run-from-tasty.blacklist" - def runTestPicklingBlacklistFile: String = "compiler/test/dotc/run-test-pickling.blacklist" + def runFromTastyExcludelistFile: String = "compiler/test/dotc/run-from-tasty.excludelist" + def runTestPicklingExcludelistFile: String = "compiler/test/dotc/run-test-pickling.excludelist" def runTestRecheckExcludesFile: String = "compiler/test/dotc/run-test-recheck.excludes" def runLazyValsAllowlistFile: String = "compiler/test/dotc/run-lazy-vals-tests.allowlist" - - def runFromTastyBlacklisted: List[String] = loadList(runFromTastyBlacklistFile) - def runTestPicklingBlacklisted: List[String] = loadList(runTestPicklingBlacklistFile) + def runFromTastyExcludelisted: List[String] = loadList(runFromTastyExcludelistFile) + def runTestPicklingExcludelisted: List[String] = loadList(runTestPicklingExcludelistFile) def runTestRecheckExcluded: List[String] = loadList(runTestRecheckExcludesFile) def runLazyValsAllowlist: List[String] = loadList(runLazyValsAllowlistFile) diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index f10e159beb86..71bf5a7e7844 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -170,8 +170,8 @@ class CompilationTests { @Test def pickling: Unit = { implicit val testGroup: TestGroup = TestGroup("testPickling") aggregateTests( - compileFilesInDir("tests/pos", picklingOptions, FileFilter.exclude(TestSources.posTestPicklingBlacklisted)), - compileFilesInDir("tests/run", picklingOptions, FileFilter.exclude(TestSources.runTestPicklingBlacklisted)) + compileFilesInDir("tests/pos", picklingOptions, FileFilter.exclude(TestSources.posTestPicklingExcludelisted)), + compileFilesInDir("tests/run", picklingOptions, FileFilter.exclude(TestSources.runTestPicklingExcludelisted)) ).checkCompile() } diff --git a/compiler/test/dotty/tools/dotc/FromTastyTests.scala b/compiler/test/dotty/tools/dotc/FromTastyTests.scala index 1d46cbbce95c..874088fb618e 100644 --- a/compiler/test/dotty/tools/dotc/FromTastyTests.scala +++ b/compiler/test/dotty/tools/dotc/FromTastyTests.scala @@ -23,7 +23,7 @@ class FromTastyTests { implicit val testGroup: TestGroup = TestGroup("posTestFromTasty") compileTastyInDir(s"tests${JFile.separator}pos", defaultOptions, - fromTastyFilter = FileFilter.exclude(TestSources.posFromTastyBlacklisted) + fromTastyFilter = FileFilter.exclude(TestSources.posFromTastyExcludelisted) ).checkCompile() } @@ -35,7 +35,7 @@ class FromTastyTests { implicit val testGroup: TestGroup = TestGroup("runTestFromTasty") compileTastyInDir(s"tests${JFile.separator}run", defaultOptions, - fromTastyFilter = FileFilter.exclude(TestSources.runFromTastyBlacklisted) + fromTastyFilter = FileFilter.exclude(TestSources.runFromTastyExcludelisted) ).checkRuns() } } diff --git a/compiler/test/dotty/tools/dotc/parsing/ScannerTest.scala b/compiler/test/dotty/tools/dotc/parsing/ScannerTest.scala index 659cd27e62f4..9f78d0778b41 100644 --- a/compiler/test/dotty/tools/dotc/parsing/ScannerTest.scala +++ b/compiler/test/dotty/tools/dotc/parsing/ScannerTest.scala @@ -10,7 +10,7 @@ import org.junit.Test class ScannerTest extends DottyTest { - val blackList = List( + val excluded = List( "/scaladoc/scala/tools/nsc/doc/html/page/Index.scala", "/scaladoc/scala/tools/nsc/doc/html/page/Template.scala" ) @@ -33,13 +33,13 @@ class ScannerTest extends DottyTest { def scanDir(path: String): Unit = scanDir(Directory(path)) def scanDir(dir: Directory): Unit = { - if (blackList exists (dir.jpath.toString endsWith _)) - println(s"blacklisted package: ${dir.toAbsolute.jpath}") + if (excluded exists (dir.jpath.toString endsWith _)) + println(s"excluded package: ${dir.toAbsolute.jpath}") else for (f <- dir.files) if (f.name.endsWith(".scala")) - if (blackList exists (f.jpath.toString endsWith _)) - println(s"blacklisted file: ${f.toAbsolute.jpath}") + if (excluded exists (f.jpath.toString endsWith _)) + println(s"excluded file: ${f.toAbsolute.jpath}") else scan(new PlainFile(f)) for (d <- dir.dirs) diff --git a/compiler/test/dotty/tools/vulpix/FileFilter.scala b/compiler/test/dotty/tools/vulpix/FileFilter.scala index b2aef8af038e..b59b4d4f209d 100644 --- a/compiler/test/dotty/tools/vulpix/FileFilter.scala +++ b/compiler/test/dotty/tools/vulpix/FileFilter.scala @@ -11,13 +11,13 @@ object FileFilter { exclude(file :: files.toList) def exclude(files: List[String]): FileFilter = new FileFilter { - private val blackList = files.toSet - def accept(file: String): Boolean = !blackList.contains(file) + private val excluded = files.toSet + def accept(file: String): Boolean = !excluded.contains(file) } def include(files: List[String]): FileFilter = new FileFilter { - private val whiteList = files.toSet - def accept(file: String): Boolean = whiteList.contains(file) + private val included = files.toSet + def accept(file: String): Boolean = included.contains(file) } object NoFilter extends FileFilter { diff --git a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala index f701a348d233..b4189deb805c 100644 --- a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala +++ b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala @@ -1499,7 +1499,7 @@ trait ParallelTesting extends RunnerOrchestration { self => | | sbt "testCompilation --from-tasty $file" | - |This tests can be disabled by adding `${file.getName}` to `compiler${JFile.separator}test${JFile.separator}dotc${JFile.separator}$runOrPos-$listName.blacklist` + |This tests can be disabled by adding `${file.getName}` to `compiler${JFile.separator}test${JFile.separator}dotc${JFile.separator}$runOrPos-$listName.excludelist` | |""".stripMargin } diff --git a/project/Build.scala b/project/Build.scala index 2e172a7e005a..7e0fe2b4c761 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -1459,7 +1459,7 @@ object Build { ) }, - // A first blacklist of tests for those that do not compile or do not link + // A first excludelist of tests for those that do not compile or do not link (Test / managedSources) ++= { val dir = fetchScalaJSSource.value / "test-suite" diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/BasicSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/BasicSupport.scala index a5e32c7332bd..81415377beeb 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/BasicSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/BasicSupport.scala @@ -42,7 +42,7 @@ trait BasicSupport: def getAnnotations(): List[Annotation] = // Custom annotations should be documented only if annotated by @java.lang.annotation.Documented // We allow also some special cases - val fqNameWhitelist = Set( + val fqNameAllowlist = Set( "scala.specialized", "scala.throws", "scala.transient", @@ -56,7 +56,7 @@ trait BasicSupport: ) val documentedSymbol = summon[Quotes].reflect.Symbol.requiredClass("java.lang.annotation.Documented") val annotations = sym.annotations.filter { a => - a.tpe.typeSymbol.hasAnnotation(documentedSymbol) || fqNameWhitelist.contains(a.symbol.fullName) + a.tpe.typeSymbol.hasAnnotation(documentedSymbol) || fqNameAllowlist.contains(a.symbol.fullName) } annotations.map(parseAnnotation).reverse From b354b70b5cb5da2b75910f363f2daf427ce09683 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Tue, 1 Apr 2025 16:27:52 +0200 Subject: [PATCH 010/505] Improve the usage of inclusive language Changes: - blacklist -> excludelist - whitelist -> allowlist Discussion: - https://github.com/scala/scala3/issues/21988 - https://github.com/scala/scala3/pull/22360#issuecomment-2587398739 [Cherry-picked 910fca9026e6b10ad07fd0fd6d1381888c3954cb][modified] From 491e4cd31e572953e5a74a988b41f2495fcd9a84 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Wed, 8 Jan 2025 14:35:33 +0000 Subject: [PATCH 011/505] Fix SeparateCompilationSource toString [Cherry-picked 7d7e2dcd0915ac69991ec4f222581fc0b6692d83] --- compiler/test/dotty/tools/vulpix/ParallelTesting.scala | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala index b4189deb805c..7d32b3d6c9fa 100644 --- a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala +++ b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala @@ -156,6 +156,11 @@ trait ParallelTesting extends RunnerOrchestration { self => } } } + + final override def toString: String = sourceFiles match { + case Array(f) => f.getPath + case _ => outDir.getPath.stripPrefix(defaultOutputDir).stripPrefix(name).stripPrefix("/") + } } /** A group of files that may all be compiled together, with the same flags @@ -170,8 +175,6 @@ trait ParallelTesting extends RunnerOrchestration { self => decompilation: Boolean = false ) extends TestSource { def sourceFiles: Array[JFile] = files.filter(isSourceFile) - - override def toString() = sourceFiles match { case Array(f) => f.getPath case _ => outDir.getPath } } /** A test source whose files will be compiled separately according to their From 2dbead67fb4b6b5a949b47914cb195136fbc7784 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Tue, 1 Apr 2025 16:29:32 +0200 Subject: [PATCH 012/505] chore: regroup all the library settings in a single function [Cherry-picked f46687e7992ae05f439976188aefa8941ac7d7e1][modified] --- project/Build.scala | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/project/Build.scala b/project/Build.scala index 7e0fe2b4c761..332dea92894f 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -959,7 +959,9 @@ object Build { } // Settings shared between scala3-library, scala3-library-bootstrapped and scala3-library-bootstrappedJS - lazy val dottyLibrarySettings = Seq( + def dottyLibrarySettings(implicit mode: Mode) = Seq( + versionScheme := Some("semver-spec"), + libraryDependencies += "org.scala-lang" % "scala-library" % stdlibVersion, (Compile / scalacOptions) ++= Seq( // Needed so that the library sources are visible when `dotty.tools.dotc.core.Definitions#init` is called "-sourcepath", (Compile / sourceDirectories).value.map(_.getAbsolutePath).distinct.mkString(File.pathSeparator), @@ -2043,16 +2045,9 @@ object Build { settings(dottyCompilerSettings) def asDottyLibrary(implicit mode: Mode): Project = { - val base = - project.withCommonSettings. - settings( - versionScheme := Some("semver-spec"), - libraryDependencies += "org.scala-lang" % "scala-library" % stdlibVersion, - // Make sure we do not refer to experimental features outside an experimental scope. - // In other words, disable NIGHTLY/SNAPSHOT experimental scope. - scalacOptions += "-Yno-experimental", - ). - settings(dottyLibrarySettings) + val base = project + .withCommonSettings + .settings(dottyLibrarySettings) if (mode == Bootstrapped) { base.settings( (Compile/doc) := { @@ -2111,6 +2106,7 @@ object Build { case NonBootstrapped => commonNonBootstrappedSettings case Bootstrapped => commonBootstrappedSettings }) + } /* Tests TASTy version invariants during NIGHLY, RC or Stable releases */ From 822a29c5098082fc225e6f64343244fe0290fd27 Mon Sep 17 00:00:00 2001 From: odersky Date: Sun, 19 Jan 2025 20:03:10 +0100 Subject: [PATCH 013/505] Fix mapping of annotations We previously did not do an (expensive) TreeTypeMap on an annotation if the mapped versions of all types of subtrees of the annotation tree were =:= to the original types. But it turns out this is too coarse. In the test we have capture set variables where we intend to map a TypeRef to a TypeParamRef but the two were considered as =:= because of the bounds they had. So no mapping took place. We now use `eql` instead of =:=, which is structural comparison with `eq` for references to corresponding binders. [Cherry-picked 6d6da118ac15b16dc58e35ce85127f468e7c4674] --- compiler/src/dotty/tools/dotc/core/Annotations.scala | 2 +- compiler/src/dotty/tools/dotc/core/Types.scala | 2 ++ tests/pos-custom-args/captures/setup/a_1.scala | 6 ++++++ tests/pos-custom-args/captures/setup/b_1.scala | 5 +++++ tests/pos-custom-args/captures/setup/b_2.scala | 5 +++++ 5 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 tests/pos-custom-args/captures/setup/a_1.scala create mode 100644 tests/pos-custom-args/captures/setup/b_1.scala create mode 100644 tests/pos-custom-args/captures/setup/b_2.scala diff --git a/compiler/src/dotty/tools/dotc/core/Annotations.scala b/compiler/src/dotty/tools/dotc/core/Annotations.scala index f5825df84a8b..0706003f533e 100644 --- a/compiler/src/dotty/tools/dotc/core/Annotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Annotations.scala @@ -65,7 +65,7 @@ object Annotations { if tm.isRange(x) then x else val tp1 = tm(tree.tpe) - foldOver(if !tp1.exists || (tp1 frozen_=:= tree.tpe) then x else tp1, tree) + foldOver(if !tp1.exists || tp1.eql(tree.tpe) then x else tp1, tree) val diff = findDiff(NoType, args) if tm.isRange(diff) then EmptyAnnotation else if diff.exists then derivedAnnotation(tm.mapOver(tree)) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 5fe6c3174c04..ac6089516571 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -5967,6 +5967,8 @@ object Types extends TypeUtils { override def stopAt = thisMap.stopAt def apply(tp: Type) = f(thisMap(tp)) } + + override def toString = s"${getClass.getSimpleName}@$hashCode" // otherwise would print as } /** A type map that maps also parents and self type of a ClassInfo */ diff --git a/tests/pos-custom-args/captures/setup/a_1.scala b/tests/pos-custom-args/captures/setup/a_1.scala new file mode 100644 index 000000000000..21afde8be3ea --- /dev/null +++ b/tests/pos-custom-args/captures/setup/a_1.scala @@ -0,0 +1,6 @@ +// a.scala +import language.experimental.captureChecking +import scala.caps.CapSet + +trait A: + def f[C^](x: AnyRef^{C^}): Unit diff --git a/tests/pos-custom-args/captures/setup/b_1.scala b/tests/pos-custom-args/captures/setup/b_1.scala new file mode 100644 index 000000000000..d5ba925970ba --- /dev/null +++ b/tests/pos-custom-args/captures/setup/b_1.scala @@ -0,0 +1,5 @@ +import language.experimental.captureChecking +import scala.caps.CapSet + +class B extends A: + def f[C^](x: AnyRef^{C^}): Unit = ??? diff --git a/tests/pos-custom-args/captures/setup/b_2.scala b/tests/pos-custom-args/captures/setup/b_2.scala new file mode 100644 index 000000000000..d5ba925970ba --- /dev/null +++ b/tests/pos-custom-args/captures/setup/b_2.scala @@ -0,0 +1,5 @@ +import language.experimental.captureChecking +import scala.caps.CapSet + +class B extends A: + def f[C^](x: AnyRef^{C^}): Unit = ??? From e92279fc0f58533b3f237ef8d66d1d59a98f6ce5 Mon Sep 17 00:00:00 2001 From: som-snytt Date: Mon, 20 Jan 2025 02:25:38 -0800 Subject: [PATCH 014/505] Suppress spurious Suppression (#22383) Guard against multiple registrations of nowarn on related elements. Fixes #18341 --- compiler/src/dotty/tools/dotc/Run.scala | 16 +++++++------- .../dotty/tools/dotc/reporting/WConf.scala | 2 +- tests/warn/i18341.scala | 21 +++++++++++++++++++ 3 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 tests/warn/i18341.scala diff --git a/compiler/src/dotty/tools/dotc/Run.scala b/compiler/src/dotty/tools/dotc/Run.scala index 8e98f276a7c2..7dace14ac068 100644 --- a/compiler/src/dotty/tools/dotc/Run.scala +++ b/compiler/src/dotty/tools/dotc/Run.scala @@ -30,7 +30,7 @@ import StdNames.nme import java.io.{BufferedWriter, OutputStreamWriter} import java.nio.charset.StandardCharsets -import scala.collection.mutable +import scala.collection.mutable, mutable.ListBuffer import scala.util.control.NonFatal import scala.io.Codec @@ -68,7 +68,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint private var myFiles: Set[AbstractFile] = _ // `@nowarn` annotations by source file, populated during typer - private val mySuppressions: mutable.LinkedHashMap[SourceFile, mutable.ListBuffer[Suppression]] = mutable.LinkedHashMap.empty + private val mySuppressions: mutable.LinkedHashMap[SourceFile, ListBuffer[Suppression]] = mutable.LinkedHashMap.empty // source files whose `@nowarn` annotations are processed private val mySuppressionsComplete: mutable.Set[SourceFile] = mutable.Set.empty // warnings issued before a source file's `@nowarn` annotations are processed, suspended so that `@nowarn` can filter them @@ -98,8 +98,9 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint } def addSuppression(sup: Suppression): Unit = - val source = sup.annotPos.source - mySuppressions.getOrElseUpdate(source, mutable.ListBuffer.empty) += sup + val suppressions = mySuppressions.getOrElseUpdate(sup.annotPos.source, ListBuffer.empty) + if sup.start != sup.end && suppressions.forall(x => x.start != sup.start || x.end != sup.end) then + suppressions += sup def reportSuspendedMessages(source: SourceFile)(using Context): Unit = { // sort suppressions. they are not added in any particular order because of lazy type completion @@ -114,11 +115,12 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint mySuspendedMessages.keysIterator.toList.foreach(reportSuspendedMessages) // report unused nowarns only if all all phases are done if !hasErrors && ctx.settings.WunusedHas.nowarn then - for { + for source <- mySuppressions.keysIterator.toList sups <- mySuppressions.remove(source) sup <- sups.reverse - } if (!sup.used) + if !sup.used + do report.warning("@nowarn annotation does not suppress any warnings", sup.annotPos) /** The compilation units currently being compiled, this may return different @@ -167,7 +169,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint val staticRefs = util.EqHashMap[Name, Denotation](initialCapacity = 1024) /** Actions that need to be performed at the end of the current compilation run */ - private var finalizeActions = mutable.ListBuffer[() => Unit]() + private var finalizeActions = ListBuffer.empty[() => Unit] private var _progress: Progress | Null = null // Set if progress reporting is enabled diff --git a/compiler/src/dotty/tools/dotc/reporting/WConf.scala b/compiler/src/dotty/tools/dotc/reporting/WConf.scala index 3842067f5390..b1afc2ab5dba 100644 --- a/compiler/src/dotty/tools/dotc/reporting/WConf.scala +++ b/compiler/src/dotty/tools/dotc/reporting/WConf.scala @@ -134,7 +134,7 @@ object WConf: if (parseErrorss.nonEmpty) Left(parseErrorss.flatten) else Right(WConf(configs)) -class Suppression(val annotPos: SourcePosition, filters: List[MessageFilter], val start: Int, end: Int, val verbose: Boolean): +class Suppression(val annotPos: SourcePosition, filters: List[MessageFilter], val start: Int, val end: Int, val verbose: Boolean): private[this] var _used = false def used: Boolean = _used def markUsed(): Unit = { _used = true } diff --git a/tests/warn/i18341.scala b/tests/warn/i18341.scala new file mode 100644 index 000000000000..63b725df000f --- /dev/null +++ b/tests/warn/i18341.scala @@ -0,0 +1,21 @@ + +//> using options -Wunused:params,nowarn + +import annotation.* + +class B(@nowarn useless: Int) + +class C(@nowarn("msg=unused") useless: Int) + +class D(useless: Int) // warn + +class E(@nowarn useful: Int): // warn + def e = useful * 10 // 10x useful + +class X: + def extensionInCompanion: String = ??? +@nowarn // extensionInCompanion +object X: + implicit def companionConversion(x: X): B = ??? + + extension (x: X) def extensionInCompanion: String = ??? From 12a27a38734783e14705fdd43e7bcd1188ff40dd Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Tue, 1 Apr 2025 16:32:13 +0200 Subject: [PATCH 015/505] Suppress spurious Suppression (#22383) Guard against multiple registrations of nowarn on related elements. Fixes #18341 [Cherry-picked a377c8a04782b9763657abc0283d27b3f364ac54][modified] From 0886974876ad228bb96919d193f8f6d609ccc140 Mon Sep 17 00:00:00 2001 From: Jan Chyb <48855024+jchyb@users.noreply.github.com> Date: Mon, 20 Jan 2025 11:57:50 +0100 Subject: [PATCH 016/505] Fix inline proxy generation for opaque types referencing other opaque types (#22381) Fixes #22359 Fixes #17243 [Cherry-picked fe2e6e9203236921c0976fcb0f891ab8d4a42d66] --- .../dotty/tools/dotc/inlines/Inliner.scala | 46 ++++++++++++++++++- tests/pos/22359a.scala | 15 ++++++ tests/pos/22359b.scala | 17 +++++++ tests/pos/i17243.scala | 17 +++++++ 4 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 tests/pos/22359a.scala create mode 100644 tests/pos/22359b.scala create mode 100644 tests/pos/i17243.scala diff --git a/compiler/src/dotty/tools/dotc/inlines/Inliner.scala b/compiler/src/dotty/tools/dotc/inlines/Inliner.scala index d83817dd90e0..5a8111a4cc28 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inliner.scala @@ -144,9 +144,28 @@ object Inliner: else Nil case _ => Nil val refinements = openOpaqueAliases(cls.givenSelfType) + + // Map references in the refinements from the proxied termRef + // to the recursive type of the refined type + // e.g.: Obj.type{type A = Obj.B; type B = Int} -> Obj.type{type A = .B; type B = Int} + def mapRecTermRefReferences(recType: RecType, refinedType: Type) = + new TypeMap { + def apply(tp: Type) = tp match + case RefinedType(a: RefinedType, b, info) => RefinedType(apply(a), b, apply(info)) + case RefinedType(a, b, info) => RefinedType(a, b, apply(info)) + case TypeRef(prefix, des) => TypeRef(apply(prefix), des) + case termRef: TermRef if termRef == ref => recType.recThis + case _ => mapOver(tp) + }.apply(refinedType) + val refinedType = refinements.foldLeft(ref: Type): (parent, refinement) => RefinedType(parent, refinement._1, TypeAlias(refinement._2)) - val refiningSym = newSym(InlineBinderName.fresh(), Synthetic, refinedType, span) + + val recType = RecType.closeOver ( recType => + mapRecTermRefReferences(recType, refinedType) + ) + + val refiningSym = newSym(InlineBinderName.fresh(), Synthetic, recType, span) refiningSym.termRef def unapply(refiningRef: TermRef)(using Context): Option[TermRef] = @@ -387,7 +406,9 @@ class Inliner(val call: tpd.Tree)(using Context): val refiningRef = OpaqueProxy(ref, cls, call.span) val refiningSym = refiningRef.symbol.asTerm val refinedType = refiningRef.info - val refiningDef = ValDef(refiningSym, tpd.ref(ref).cast(refinedType), inferred = true).withSpan(span) + val refiningDef = addProxiesForRecurrentOpaques( + ValDef(refiningSym, tpd.ref(ref).cast(refinedType), inferred = true).withSpan(span) + ) inlining.println(i"add opaque alias proxy $refiningDef for $ref in $tp") bindingsBuf += refiningDef opaqueProxies += ((ref, refiningSym.termRef)) @@ -407,6 +428,27 @@ class Inliner(val call: tpd.Tree)(using Context): } ) + /** Transforms proxies that reference other opaque types, like for: + * object Obj1 { opaque type A = Int } + * object Obj2 { opaque type B = A } + * and proxy$1 of type Obj2.type{type B = Obj1.A} + * creates proxy$2 of type Obj1.type{type A = Int} + * and transforms proxy$1 into Obj2.type{type B = proxy$2.A} + */ + private def addProxiesForRecurrentOpaques(binding: ValDef)(using Context): ValDef = + def fixRefinedTypes(ref: Type): Unit = + ref match + case recType: RecType => fixRefinedTypes(recType.underlying) + case RefinedType(parent, name, info) => + addOpaqueProxies(info.widen, binding.span, true) + fixRefinedTypes(parent) + case _ => + fixRefinedTypes(binding.symbol.info) + binding.symbol.info = mapOpaques.typeMap(binding.symbol.info) + mapOpaques.transform(binding).asInstanceOf[ValDef] + .showing(i"transformed this binding exposing opaque aliases: $result", inlining) + end addProxiesForRecurrentOpaques + /** If `binding` contains TermRefs that refer to objects with opaque * type aliases, add proxy definitions that expose these aliases * and substitute such TermRefs with theproxies. Example from pos/opaque-inline1.scala: diff --git a/tests/pos/22359a.scala b/tests/pos/22359a.scala new file mode 100644 index 000000000000..a3b9ef63257a --- /dev/null +++ b/tests/pos/22359a.scala @@ -0,0 +1,15 @@ +opaque type NT[N <: Tuple, V <: Tuple] = V +opaque type System = NT[Tuple1["wires"], Tuple1[Any]] + +extension [N <: Tuple, V <: Tuple] (x: NT[N, V]) { + inline def apply(n: Int): Any = + x.productElement(n) +} + +extension (system: System) { + inline def foo = + system.apply(0) +} + +val simulation: System = ??? +val _ = simulation.foo diff --git a/tests/pos/22359b.scala b/tests/pos/22359b.scala new file mode 100644 index 000000000000..f6b7cbb462c1 --- /dev/null +++ b/tests/pos/22359b.scala @@ -0,0 +1,17 @@ +object Obj2: + opaque type NT[N <: Tuple, V <: Tuple] = V + + extension [N <: Tuple, V <: Tuple] (x: NT[N, V]) { + inline def apply(n: Int): Any = + x.productElement(n) + } + +object Obj: + opaque type System = Obj2.NT[Tuple1["wires"], Tuple1[Any]] + + extension (system: System) { + inline def foo = system.apply(0) + } +import Obj._ +val simulation: System = ??? +val _ = simulation.foo diff --git a/tests/pos/i17243.scala b/tests/pos/i17243.scala new file mode 100644 index 000000000000..3d42495b26b0 --- /dev/null +++ b/tests/pos/i17243.scala @@ -0,0 +1,17 @@ +object Opaque: + opaque type A = Int + + val va: A = 1 + + inline def a(x: A) = + x + 1 + +object Opaque2: + opaque type B = Opaque.A + + val vb: B = Opaque.va + + inline def b(x: B) = Opaque.a(x) + +@main def Test() = + print(Opaque2.b(Opaque2.vb)) From a4a9dff62dab7625c6df37a6b1c6fe580a4e6f00 Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Mon, 20 Jan 2025 12:03:28 +0100 Subject: [PATCH 017/505] Only check logicalOwners for methods, and not for classes, when looking for proxies (#22356) possible fix for #21931 [Cherry-picked 08442e883b0dacdbc60c6f697e2467bfdf1643cd] --- .../dotty/tools/dotc/transform/Dependencies.scala | 2 +- .../src/dotty/tools/dotc/transform/LambdaLift.scala | 4 +++- tests/pos/i21931.scala | 13 +++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 tests/pos/i21931.scala diff --git a/compiler/src/dotty/tools/dotc/transform/Dependencies.scala b/compiler/src/dotty/tools/dotc/transform/Dependencies.scala index 733f4601e363..28fd21200759 100644 --- a/compiler/src/dotty/tools/dotc/transform/Dependencies.scala +++ b/compiler/src/dotty/tools/dotc/transform/Dependencies.scala @@ -29,7 +29,7 @@ abstract class Dependencies(root: ast.tpd.Tree, @constructorOnly rootContext: Co def tracked: Iterable[Symbol] = free.keys /** The outermost class that captures all free variables of a function - * that are captured by enclosinh classes (this means that the function could + * that are captured by enclosing classes (this means that the function could * be placed in that class without having to add more environment parameters) */ def logicalOwner: collection.Map[Symbol, Symbol] = logicOwner diff --git a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala index 3fbdf1fa5427..6a7dee2ff4fe 100644 --- a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala +++ b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala @@ -127,7 +127,9 @@ object LambdaLift: private def proxy(sym: Symbol)(using Context): Symbol = { def liftedEnclosure(sym: Symbol) = - deps.logicalOwner.getOrElse(sym, sym.enclosure) + if sym.is(Method) + then deps.logicalOwner.getOrElse(sym, sym.enclosure) + else sym.enclosure def searchIn(enclosure: Symbol): Symbol = { if (!enclosure.exists) { def enclosures(encl: Symbol): List[Symbol] = diff --git a/tests/pos/i21931.scala b/tests/pos/i21931.scala new file mode 100644 index 000000000000..6765768874af --- /dev/null +++ b/tests/pos/i21931.scala @@ -0,0 +1,13 @@ +def f() = + val NotFound: Char = 'a' + class crashing() { + class issue() { + NotFound + } + class Module() { + val obligatory = + class anonIssue() { + issue() + } + } + } From 987a8eccb1643cd7b5cfdcc298e51cb7f51580f8 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Tue, 1 Apr 2025 16:49:44 +0200 Subject: [PATCH 018/505] chore: Update versions to allow work on 3.3.7 --- project/Build.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project/Build.scala b/project/Build.scala index 2e172a7e005a..ec0c4ea2a252 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -88,7 +88,7 @@ object Build { * * Warning: Change of this variable needs to be consulted with `expectedTastyVersion` */ - val referenceVersion = "3.3.5" + val referenceVersion = "3.3.6-RC1" /** Version of the Scala compiler targeted in the current release cycle * Contains a version without RC/SNAPSHOT/NIGHTLY specific suffixes @@ -99,7 +99,7 @@ object Build { * * Warning: Change of this variable might require updating `expectedTastyVersion` */ - val developedVersion = "3.3.6" + val developedVersion = "3.3.7" /** The version of the compiler including the RC prefix. * Defined as common base before calculating environment specific suffixes in `dottyVersion` From 2881275cb289cdf2eb31b8d82476c1b0e72b54cd Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Tue, 1 Apr 2025 16:46:47 +0200 Subject: [PATCH 019/505] bugfix: Fix issues after backporting - remove named tuples specific parts (we anyway try to port as much as possible to avoid conflicts in the future) - add isTransparent method which was probably added in some incompatible PR --- .../src/dotty/tools/dotc/core/TypeUtils.scala | 10 ++ .../dotc/neg-best-effort-pickling.excludelist | 23 ---- .../neg-best-effort-unpickling.excludelist | 17 --- .../test/dotc/pos-test-pickling.blacklist | 120 ------------------ .../test/dotc/pos-test-pickling.excludelist | 3 + .../test/dotc/run-test-pickling.blacklist | 52 -------- .../main/dotty/tools/pc/HoverProvider.scala | 22 +--- .../dotty/tools/pc/MetalsInteractive.scala | 14 -- .../tests/definition/PcDefinitionSuite.scala | 9 -- .../tools/pc/tests/hover/HoverTermSuite.scala | 29 ----- .../pos-custom-args/captures/setup/a_1.scala | 6 - .../pos-custom-args/captures/setup/b_1.scala | 5 - .../pos-custom-args/captures/setup/b_2.scala | 5 - 13 files changed, 16 insertions(+), 299 deletions(-) delete mode 100644 compiler/test/dotc/neg-best-effort-pickling.excludelist delete mode 100644 compiler/test/dotc/neg-best-effort-unpickling.excludelist delete mode 100644 compiler/test/dotc/pos-test-pickling.blacklist delete mode 100644 compiler/test/dotc/run-test-pickling.blacklist delete mode 100644 tests/pos-custom-args/captures/setup/a_1.scala delete mode 100644 tests/pos-custom-args/captures/setup/b_1.scala delete mode 100644 tests/pos-custom-args/captures/setup/b_2.scala diff --git a/compiler/src/dotty/tools/dotc/core/TypeUtils.scala b/compiler/src/dotty/tools/dotc/core/TypeUtils.scala index 41d6bf1f4fae..73acc24c38c2 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeUtils.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeUtils.scala @@ -127,6 +127,16 @@ class TypeUtils: case mt: MethodType => mt.isImplicitMethod || mt.resType.takesImplicitParams case _ => false + /** Is this a type deriving only from transparent classes? + * @param traitOnly if true, all class symbols must be transparent traits + */ + def isTransparent(traitOnly: Boolean = false)(using Context): Boolean = self match + case AndType(tp1, tp2) => + tp1.isTransparent(traitOnly) && tp2.isTransparent(traitOnly) + case _ => + val cls = self.underlyingClassRef(refinementOK = false).typeSymbol + cls.isTransparentClass && (!traitOnly || cls.is(Trait)) + /** The constructors of this type that are applicable to `argTypes`, without needing * an implicit conversion. Curried constructors are always excluded. * @param adaptVarargs if true, allow a constructor with just a varargs argument to diff --git a/compiler/test/dotc/neg-best-effort-pickling.excludelist b/compiler/test/dotc/neg-best-effort-pickling.excludelist deleted file mode 100644 index 99a83a467f08..000000000000 --- a/compiler/test/dotc/neg-best-effort-pickling.excludelist +++ /dev/null @@ -1,23 +0,0 @@ -export-in-extension.scala -i12456.scala -i8623.scala -i1642.scala -i16696.scala -constructor-proxy-values.scala -i9328.scala -i15414.scala -i6796.scala -i14013.scala -toplevel-cyclic -curried-dependent-ift.scala -i17121.scala -illegal-match-types.scala -i13780-1.scala -i20317a.scala -i11226.scala -i974.scala -i13864.scala - -# semantic db generation fails in the first compilation -i1642.scala -i15158.scala diff --git a/compiler/test/dotc/neg-best-effort-unpickling.excludelist b/compiler/test/dotc/neg-best-effort-unpickling.excludelist deleted file mode 100644 index 1e22d919f25a..000000000000 --- a/compiler/test/dotc/neg-best-effort-unpickling.excludelist +++ /dev/null @@ -1,17 +0,0 @@ -# cyclic reference crashes -i4368.scala -i827.scala -cycles.scala -i5332.scala -i4369c.scala -i1806.scala -i0091-infpaths.scala -exports.scala -i14834.scala - -# other type related crashes -i4653.scala -overrideClass.scala - -# repeating on a top level type definition -i18750.scala diff --git a/compiler/test/dotc/pos-test-pickling.blacklist b/compiler/test/dotc/pos-test-pickling.blacklist deleted file mode 100644 index 1cb73da4c2eb..000000000000 --- a/compiler/test/dotc/pos-test-pickling.blacklist +++ /dev/null @@ -1,120 +0,0 @@ -i94-nada.scala -i1812.scala -i1867.scala -i3067.scala -t2712-5.scala -t284-pos.scala -t3249 -t3486 -t3612.scala -reference -scala-days-2019-slides -i7048e.scala -i8052.scala -tuple-filter.scala -i7740a.scala -i7740b.scala -i6507b.scala -i12299a.scala -i13871.scala -i15181.scala -i15922.scala -i15926.scala -t5031_2.scala -i16997.scala -i7414.scala -i17588.scala -i9804.scala -i13433.scala -i16649-irrefutable.scala -strict-pattern-bindings-3.0-migration.scala -i17255 -i17735.scala - -# Tree is huge and blows stack for printing Text -i7034.scala - -# Stale symbol: package object scala -seqtype-cycle - -# type of super reference changes due to late addition of Mirror.Singleton -i939.scala -i13332super.scala - -# Match types -i7872.scala -i11236.scala -i11247.scala -i11250 -i9999.scala -8649.scala -12093.scala -9757.scala -9890.scala -13491.scala -7512.scala -i6505.scala -i15158.scala -i15155.scala -i15827.scala -i18211.scala -i20897.scala - -# Opaque type -i5720.scala - -# Tuples -toexproftuple.scala -i7580.scala - -# Nullability -nullable.scala - -# parameter untupling with overloaded functions (see comment in Applications.normArg) -i7757.scala - -# splice type tag dealiased in this reference -i8651b.scala - -# uneliminated @uncheckedVariance after pickling -annot-bootstrap.scala - -# interaction with Scala-2's implicitly -i9793.scala - -# lazy_implicit symbol has different position after pickling -i8182.scala - -# local lifted value in annotation argument has different position after pickling -i2797a - -# Late instantiation of type variable in tryInsertImplicitOnQualifier -# allows to simplify a type that was already computed -i13842.scala - -# Position change under captureChecking -boxmap-paper.scala - -# Function types print differnt after unpickling since test mispredicts Feature.preFundsEnabled -caps-universal.scala - -# GADT cast applied to singleton type difference -i4176-gadt.scala - -# GADT difference -i13974a.scala - -java-inherited-type1 - -# recursion limit exceeded -i7445b.scala - -# more aggresive reduce projection makes a difference -i15525.scala -i19955a.scala -i19955b.scala -i20053b.scala - - -# LTS specific -i21390.TrieMap.scala diff --git a/compiler/test/dotc/pos-test-pickling.excludelist b/compiler/test/dotc/pos-test-pickling.excludelist index 23c79affada0..8f09dc61609b 100644 --- a/compiler/test/dotc/pos-test-pickling.excludelist +++ b/compiler/test/dotc/pos-test-pickling.excludelist @@ -141,3 +141,6 @@ hylolib # typecheckErrors method unpickling i21415.scala + +# LTS specific +i21390.TrieMap.scala diff --git a/compiler/test/dotc/run-test-pickling.blacklist b/compiler/test/dotc/run-test-pickling.blacklist deleted file mode 100644 index 32fa44d0cb20..000000000000 --- a/compiler/test/dotc/run-test-pickling.blacklist +++ /dev/null @@ -1,52 +0,0 @@ -## Many of these tests fail because CompilationTests.pickling does not handle -## tests containing java files correctly - -derive-generic.scala -eff-dependent.scala -enum-java -i5257.scala -i7212 -i7868.scala -i9011.scala -i9473.scala -i13433.scala -i13433b.scala -macros-in-same-project1 -mixin-forwarder-overload -t10889 -t3452d -t3452e -t3452g -t7374 -t8905 -tuple-drop.scala -tuple-ops.scala -tuple-ops.scala -tuple-take.scala -tuple-zip.scala -tuples1.scala -tuples1a.scala -tuples1b.scala -typeCheckErrors.scala -typeclass-derivation-doc-example.scala -typeclass-derivation1.scala -typeclass-derivation2.scala -typeclass-derivation2a.scala -typeclass-derivation2b.scala -typeclass-derivation2c.scala -typeclass-derivation2d.scala -typeclass-derivation3.scala -varargs-abstract -zero-arity-case-class.scala -i12194.scala -i12753 -t6138 -t6138-2 -i12656.scala -trait-static-forwarder -i17255 - -# typecheckErrors method unpickling -typeCheckErrors.scala -i18150.scala - diff --git a/presentation-compiler/src/main/dotty/tools/pc/HoverProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/HoverProvider.scala index 769eaf024862..f8249aebf68c 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/HoverProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/HoverProvider.scala @@ -107,7 +107,7 @@ object HoverProvider: case (symbol, tpe, _) :: _ if symbol.name == nme.selectDynamic || symbol.name == nme.applyDynamic => fallbackToDynamics(path, printer, contentType) - case symbolTpes @ ((symbol, tpe, None) :: _) => + case symbolTpes @ ((symbol, tpe, _) :: _) => val exprTpw = tpe.widenTermRefExpr.deepDealias val hoverString = tpw match @@ -153,21 +153,6 @@ object HoverProvider: case _ => ju.Optional.empty().nn end match - case (_, tpe, Some(namedTupleArg)) :: _ => - val exprTpw = tpe.widenTermRefExpr.deepDealias - printer.expressionType(exprTpw) match - case Some(tpe) => - ju.Optional.of( - new ScalaHover( - expressionType = Some(tpe), - symbolSignature = Some(s"$namedTupleArg: $tpe"), - docstring = None, - forceExpressionType = false, - contextInfo = printer.getUsedRenamesInfo, - contentType = contentType - ) - ).nn - case _ => ju.Optional.empty().nn end match end if end hover @@ -183,7 +168,7 @@ object HoverProvider: case SelectDynamicExtractor(sel, n, name, rest) => def findRefinement(tp: Type): Option[HoverSignature] = tp match - case RefinedType(_, refName, tpe) if (name == refName.toString() || refName.toString() == nme.Fields.toString()) => + case RefinedType(_, refName, tpe) if name == refName.toString() => val resultType = rest match case Select(_, asInstanceOf) :: TypeApply(_, List(tpe)) :: _ if asInstanceOf == nme.asInstanceOfPM => @@ -196,8 +181,7 @@ object HoverProvider: else printer.tpe(resultType) val valOrDef = - if refName.toString() == nme.Fields.toString() then "" - else if n == nme.selectDynamic && !tpe.isInstanceOf[ExprType] + if n == nme.selectDynamic && !tpe.isInstanceOf[ExprType] then "val " else "def " diff --git a/presentation-compiler/src/main/dotty/tools/pc/MetalsInteractive.scala b/presentation-compiler/src/main/dotty/tools/pc/MetalsInteractive.scala index a24ed5c7c9e7..dc4fa0446715 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/MetalsInteractive.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/MetalsInteractive.scala @@ -203,20 +203,6 @@ object MetalsInteractive: case _ => Nil - // Handle select on named tuples - case (Apply(Apply(TypeApply(fun, List(t1, t2)), List(ddef)), List(Literal(Constant(i: Int))))) :: _ - if fun.symbol.exists && fun.symbol.name == nme.apply && - fun.symbol.owner.exists && fun.symbol.owner == getModuleIfDefined("scala.NamedTuple").moduleClass => - def getIndex(t: Tree): Option[Type] = - t.tpe.dealias match - case AppliedType(_, args) => args.get(i) - case _ => None - val name = getIndex(t1) match - case Some(c: ConstantType) => c.value.stringValue - case _ => "" - val tpe = getIndex(t2).getOrElse(NoType) - List((ddef.symbol, tpe, Some(name))) - case path @ head :: tail => if head.symbol.is(Exported) then val sym = head.symbol.sourceSymbol diff --git a/presentation-compiler/test/dotty/tools/pc/tests/definition/PcDefinitionSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/definition/PcDefinitionSuite.scala index ff4c6ec25e27..fab21ffdee0a 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/definition/PcDefinitionSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/definition/PcDefinitionSuite.scala @@ -504,12 +504,3 @@ class PcDefinitionSuite extends BasePcDefinitionSuite: |val a = MyIntOut(1).un@@even |""".stripMargin, ) - - @Test def `named-tuples` = - check( - """|import scala.language.experimental.namedTuples - | - |val <> = (name = "Bob", age = 42, height = 1.9d) - |val foo_name = foo.na@@me - |""".stripMargin - ) diff --git a/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTermSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTermSuite.scala index 5e20045babfb..6f682139506e 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTermSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTermSuite.scala @@ -718,32 +718,3 @@ class HoverTermSuite extends BaseHoverSuite: """def ???: Nothing""".stripMargin.hover ) - @Test def `named-tuples`: Unit = - check( - """import scala.language.experimental.namedTuples - | - |val foo = (name = "Bob", age = 42, height = 1.9d) - |val foo_name = foo.na@@me - |""".stripMargin, - "name: String".hover - ) - - @Test def `named-tuples2`: Unit = - check( - """|import scala.language.experimental.namedTuples - | - |import NamedTuple.* - | - |class NamedTupleSelectable extends Selectable { - | type Fields <: AnyNamedTuple - | def selectDynamic(name: String): Any = ??? - |} - | - |val person = new NamedTupleSelectable { - | type Fields = (name: String, city: String) - |} - | - |val person_name = person.na@@me - |""".stripMargin, - "name: String".hover - ) diff --git a/tests/pos-custom-args/captures/setup/a_1.scala b/tests/pos-custom-args/captures/setup/a_1.scala deleted file mode 100644 index 21afde8be3ea..000000000000 --- a/tests/pos-custom-args/captures/setup/a_1.scala +++ /dev/null @@ -1,6 +0,0 @@ -// a.scala -import language.experimental.captureChecking -import scala.caps.CapSet - -trait A: - def f[C^](x: AnyRef^{C^}): Unit diff --git a/tests/pos-custom-args/captures/setup/b_1.scala b/tests/pos-custom-args/captures/setup/b_1.scala deleted file mode 100644 index d5ba925970ba..000000000000 --- a/tests/pos-custom-args/captures/setup/b_1.scala +++ /dev/null @@ -1,5 +0,0 @@ -import language.experimental.captureChecking -import scala.caps.CapSet - -class B extends A: - def f[C^](x: AnyRef^{C^}): Unit = ??? diff --git a/tests/pos-custom-args/captures/setup/b_2.scala b/tests/pos-custom-args/captures/setup/b_2.scala deleted file mode 100644 index d5ba925970ba..000000000000 --- a/tests/pos-custom-args/captures/setup/b_2.scala +++ /dev/null @@ -1,5 +0,0 @@ -import language.experimental.captureChecking -import scala.caps.CapSet - -class B extends A: - def f[C^](x: AnyRef^{C^}): Unit = ??? From db7ebdf460fd0db053d4dc6569dcc492244b411a Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Mon, 20 Jan 2025 16:17:04 +0100 Subject: [PATCH 020/505] Fix chocolatey-test when used in stable releases --- .github/workflows/ci.yaml | 8 ++++---- .github/workflows/test-chocolatey.yml | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9239020335e7..b22a44c7db7c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -782,14 +782,14 @@ jobs: uses: ./.github/workflows/build-chocolatey.yml needs: [ build-sdk-package ] with: - version: 3.3.5-local # unused - url : https://api.github.com/repos/scala/scala3/actions/artifacts/${{ needs.build-sdk-package.outputs.universal-id }}/zip - digest : ${{ needs.build-sdk-package.outputs.universal-digest }} + version: 3.3.7-SNAPSHOT # Fake version, used only for choco tests + url : https://api.github.com/repos/scala/scala3/actions/artifacts/${{ needs.build-sdk-package.outputs.win-x86_64-id }}/zip + digest : ${{ needs.build-sdk-package.outputs.win-x86_64-digest }} test-chocolatey-package: uses: ./.github/workflows/test-chocolatey.yml with: - version : 3.3.5-local # unused + version : 3.3.7-SNAPSHOT # Fake version, used only for choco tests java-version: 8 if: github.event_name == 'pull_request' && contains(github.event.pull_request.body, '[test_chocolatey]') needs: [ build-chocolatey-package ] diff --git a/.github/workflows/test-chocolatey.yml b/.github/workflows/test-chocolatey.yml index b6ca9bf74b12..e302968b9129 100644 --- a/.github/workflows/test-chocolatey.yml +++ b/.github/workflows/test-chocolatey.yml @@ -21,7 +21,10 @@ on: env: CHOCOLATEY-REPOSITORY: chocolatey-pkgs - DOTTY_CI_INSTALLATION: ${{ secrets.GITHUB_TOKEN }} + # Controls behaviour of chocolatey{Install,Uninstall}.ps1 scripts + # During snapshot releases it uses a different layout and requires access token to GH Actions artifacts + # During stable releases it uses publically available archives + DOTTY_CI_INSTALLATION: ${{ endsWith(inputs.version, '-SNAPSHOT') && secrets.GITHUB_TOKEN || '' }} jobs: test: From 85f54f1d2c239d7951deb47cd8fa21946d65d5c1 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Thu, 3 Apr 2025 20:19:13 +0200 Subject: [PATCH 021/505] Fix chocolatey-test when used in stable releases [Cherry-picked 11238467eeffa9a2741668543a48a913fbf6f6e3][modified] From 75450da4c18ac177b997bfb4f061b571bf8cdc07 Mon Sep 17 00:00:00 2001 From: fan-tom Date: Fri, 17 Jan 2025 01:50:02 +0400 Subject: [PATCH 022/505] fix: annotations are not expected in the middle of an array type by java parser Java parser doesn't expect an annotation in the next types, while it should: - `Object @my.Ann []` - `Object @my.Ann [] @my.OtherAnn []` closes #19642 [Cherry-picked 9c971be202ab73688dbcff50a8240cb2878097aa] --- .../dotty/tools/dotc/parsing/JavaParsers.scala | 6 ++++-- tests/pos/i19642/Valid.java | 17 +++++++++++++++++ tests/pos/i19642/i19642.java | 9 +++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 tests/pos/i19642/Valid.java create mode 100644 tests/pos/i19642/i19642.java diff --git a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala index 092ab2eeea0d..1556b31e4ce8 100644 --- a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala @@ -254,7 +254,8 @@ object JavaParsers { t } - def optArrayBrackets(tpt: Tree): Tree = + def optArrayBrackets(tpt: Tree): Tree = { + annotations() if (in.token == LBRACKET) { val tpt1 = atSpan(tpt.span.start, in.offset) { arrayOf(tpt) } in.nextToken() @@ -262,6 +263,7 @@ object JavaParsers { optArrayBrackets(tpt1) } else tpt + } def basicType(): Tree = atSpan(in.offset) { @@ -335,7 +337,7 @@ object JavaParsers { } def annotations(): List[Tree] = { - var annots = new ListBuffer[Tree] + val annots = new ListBuffer[Tree] while (in.token == AT) { in.nextToken() annotation() match { diff --git a/tests/pos/i19642/Valid.java b/tests/pos/i19642/Valid.java new file mode 100644 index 000000000000..17e0e1173726 --- /dev/null +++ b/tests/pos/i19642/Valid.java @@ -0,0 +1,17 @@ +package lib; + +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.TYPE_USE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Target({ METHOD, FIELD, CONSTRUCTOR, PARAMETER, TYPE_USE }) +@Retention(RUNTIME) +@Documented +public @interface Valid {} diff --git a/tests/pos/i19642/i19642.java b/tests/pos/i19642/i19642.java new file mode 100644 index 000000000000..c7d8ba9f0e72 --- /dev/null +++ b/tests/pos/i19642/i19642.java @@ -0,0 +1,9 @@ +package app; + +import java.util.Optional; +import lib.*; + +public class i19642 { + private String @lib.Valid [] flatArray; + private String @lib.Valid [] @lib.Valid [] nestedArray; +} From 6fa34a22a77f5a31ad42aa46bb07431cce4a71df Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Thu, 3 Apr 2025 20:21:51 +0200 Subject: [PATCH 023/505] Fix cyclic check, regardless of definition order [Cherry-picked 2bdf8dd59079f46295665dd0528cd37bffafc09a][modified] --- .../src/dotty/tools/dotc/typer/Checking.scala | 32 +++++++++--- tests/neg/i4368.scala | 6 +-- tests/neg/i4369c.scala | 17 +++++- tests/neg/toplevel-cyclic/defs_1.scala | 2 +- tests/neg/toplevel-cyclic/moredefs_1.scala | 2 +- tests/pos/i22257.fixed.scala | 52 +++++++++++++++++++ tests/pos/i22257.orig.scala | 52 +++++++++++++++++++ tests/pos/i22257.scala | 26 ++++++++++ 8 files changed, 175 insertions(+), 14 deletions(-) create mode 100644 tests/pos/i22257.fixed.scala create mode 100644 tests/pos/i22257.orig.scala create mode 100644 tests/pos/i22257.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index bf99def353b0..2757304f32e8 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -274,11 +274,16 @@ object Checking { */ def checkInfo(tp: Type): Type = tp match { case tp @ TypeAlias(alias) => - tp.derivedAlias(checkPart(alias, "alias")) + val lo1 = atVariance(-1)(checkPart(alias, "alias")) + val hi1 = checkUpper(alias, "alias") + if lo1 eq hi1 then + tp.derivedAlias(lo1) + else + tp.derivedTypeBounds(lo1, hi1) case tp @ MatchAlias(alias) => - tp.derivedAlias(checkUpper(alias, "match")) + tp.derivedAlias(atVariance(0)(checkUpper(alias, "match"))) case tp @ TypeBounds(lo, hi) => - tp.derivedTypeBounds(checkPart(lo, "lower bound"), checkUpper(hi, "upper bound")) + tp.derivedTypeBounds(atVariance(-1)(checkPart(lo, "lower bound")), checkUpper(hi, "upper bound")) case _ => tp } @@ -299,12 +304,12 @@ object Checking { case tp: TermRef => this(tp.info) mapOver(tp) - case tp @ AppliedType(tycon, args) => - tp.derivedAppliedType(this(tycon), args.mapConserve(this(_, nestedCycleOK, nestedCycleOK))) case tp @ RefinedType(parent, name, rinfo) => tp.derivedRefinedType(this(parent), name, this(rinfo, nestedCycleOK, nestedCycleOK)) case tp: RecType => tp.rebind(this(tp.parent)) + case tp: LazyRef => + tp case tp @ TypeRef(pre, _) => try { // A prefix is interesting if it might contain (transitively) a reference @@ -337,14 +342,17 @@ object Checking { if isInteresting(pre) then CyclicReference.trace(i"explore ${tp.symbol} for cyclic references"): - val pre1 = this(pre, false, false) + val pre1 = atVariance(variance max 0)(this(pre, false, false)) if locked.contains(tp) || tp.symbol.infoOrCompleter.isInstanceOf[NoCompleter] + && tp.symbol == sym then throw CyclicReference(tp.symbol) locked += tp try - if tp.symbol.isOpaqueAlias then + if tp.symbol.infoOrCompleter.isInstanceOf[NoCompleter] then + ; // skip checking info (and avoid forcing the symbol with .isOpaqueAlias/etc) + else if tp.symbol.isOpaqueAlias then checkInfo(TypeAlias(tp.translucentSuperType)) else if !tp.symbol.isClass then checkInfo(tp.info) @@ -362,6 +370,16 @@ object Checking { } case _ => mapOver(tp) } + + override def mapArg(arg: Type, tparam: ParamInfo): Type = + val varianceDiff = variance != tparam.paramVarianceSign + atVariance(variance * tparam.paramVarianceSign): + // Using tests/pos/i22257.scala as an example, + // if we consider FP's lower-bound of Fixed[Node] + // than `Node` is a type argument in contravariant + // position, while the type parameter is covariant. + val nestedCycleOK1 = nestedCycleOK || variance != 0 && varianceDiff + this(arg, nestedCycleOK, nestedCycleOK1) } /** Under -Yrequire-targetName, if `sym` has an operator name, check that it has a diff --git a/tests/neg/i4368.scala b/tests/neg/i4368.scala index 95c342d5fe2a..6718aece4eba 100644 --- a/tests/neg/i4368.scala +++ b/tests/neg/i4368.scala @@ -98,7 +98,7 @@ object Test6 { object Test7 { class Fix[F[_]] { - class Foo { type R >: F[T] <: F[T] } // error: cyclic + class Foo { type R >: F[T] <: F[T] } // error type T = F[Foo#R] } @@ -149,9 +149,9 @@ object Test9 { object i4369 { trait X { self => type R <: Z - type Z >: X { type R = self.R; type Z = self.R } // error: cyclic // error: cyclic // error: cyclic + type Z >: X { type R = self.R; type Z = self.R } // error: cyclic } - class Foo extends X { type R = Foo; type Z = Foo } + class Foo extends X { type R = Foo; type Z = Foo } // error } object i4370 { class Foo { type R = A } diff --git a/tests/neg/i4369c.scala b/tests/neg/i4369c.scala index a2bfbcb598d6..06a77d51cdbe 100644 --- a/tests/neg/i4369c.scala +++ b/tests/neg/i4369c.scala @@ -1,5 +1,18 @@ trait X { self => type R <: Z - type Z >: X { type R = self.R; type Z = self.R } // error // error // error + type Z >: + X { // error + type R = // was-error + self.R + type Z = // was-error + self.R + } +} + +class Foo // error + extends X { + type R = + Foo + type Z = + Foo } -class Foo extends X { type R = Foo; type Z = Foo } diff --git a/tests/neg/toplevel-cyclic/defs_1.scala b/tests/neg/toplevel-cyclic/defs_1.scala index 34b0475066b0..f40fa5bdebdd 100644 --- a/tests/neg/toplevel-cyclic/defs_1.scala +++ b/tests/neg/toplevel-cyclic/defs_1.scala @@ -1 +1 @@ -type A = B +type A = B // error: recursion limit exceeded diff --git a/tests/neg/toplevel-cyclic/moredefs_1.scala b/tests/neg/toplevel-cyclic/moredefs_1.scala index 3c8c3de93aa7..91360d0c0f4d 100644 --- a/tests/neg/toplevel-cyclic/moredefs_1.scala +++ b/tests/neg/toplevel-cyclic/moredefs_1.scala @@ -1 +1 @@ -type B = A // error: recursion limit exceeded +type B = A diff --git a/tests/pos/i22257.fixed.scala b/tests/pos/i22257.fixed.scala new file mode 100644 index 000000000000..d0fa1a0e81cb --- /dev/null +++ b/tests/pos/i22257.fixed.scala @@ -0,0 +1,52 @@ + +object Scaffold { + + trait Arrow + object Arrow { + trait Outbound extends Arrow + } + + trait NodeKOrGraphK {} + + trait NodeK extends NodeKOrGraphK { + + type FBound <: Induction + + protected def getInduction: Seq[FBound] + } + + trait Induction { + def arrow: Arrow + def node: NodeK + } + + object Induction { + + trait FP[+N <: NodeK] extends Induction { // short for "fixed point" + def node: N + } + } + + trait GraphK extends NodeKOrGraphK { + + type Batch[+T] <: Iterable[T] + + type _Node <: NodeK + + def entries: Batch[_Node] + } + + trait Topology { + + type Node = NodeK { type FBound <: Topology.this.FBound } + trait Node_ extends NodeK { + type FBound = Topology.this.FBound + } + + type FP = Induction.FP[Node] + type FBound <: FP + + type Graph = GraphK { type _Node <: Node } + } + +} diff --git a/tests/pos/i22257.orig.scala b/tests/pos/i22257.orig.scala new file mode 100644 index 000000000000..0be8d02d5a85 --- /dev/null +++ b/tests/pos/i22257.orig.scala @@ -0,0 +1,52 @@ + +object Scaffold { + + trait Arrow + object Arrow { + trait Outbound extends Arrow + } + + trait NodeKOrGraphK {} + + trait NodeK extends NodeKOrGraphK { + + type FBound <: Induction + + protected def getInduction: Seq[FBound] + } + + trait Induction { + def arrow: Arrow + def node: NodeK + } + + object Induction { + + trait FP[+N <: NodeK] extends Induction { // short for "fixed point" + def node: N + } + } + + trait GraphK extends NodeKOrGraphK { + + type Batch[+T] <: Iterable[T] + + type _Node <: NodeK + + def entries: Batch[_Node] + } + + trait Topology { + + type FP = Induction.FP[Node] + type FBound <: FP + + type Node = NodeK { type FBound <: Topology.this.FBound } + trait Node_ extends NodeK { + type FBound = Topology.this.FBound + } + + type Graph = GraphK { type _Node <: Node } + } + +} diff --git a/tests/pos/i22257.scala b/tests/pos/i22257.scala new file mode 100644 index 000000000000..8cd797529097 --- /dev/null +++ b/tests/pos/i22257.scala @@ -0,0 +1,26 @@ +trait NodeK { type FBound } +trait Fixed[+N <: NodeK] + +type Bound1 <: FP1 +type FP1 = Fixed[Node1] +type Node1 = NodeK { type FBound <: Bound1 } // was-error + +type FP2 = Fixed[Node2] // was-error +type Bound2 <: FP2 +type Node2 = NodeK { type FBound <: Bound2 } + +type Node3 = NodeK { type FBound <: Bound3 } +type FP3 = Fixed[Node3] +type Bound3 <: FP3 + +type Bound4 <: FP4 +type Node4 = NodeK { type FBound <: Bound4 } // was-error +type FP4 = Fixed[Node4] + +type FP5 = Fixed[Node5] // was-error +type Node5 = NodeK { type FBound <: Bound5 } +type Bound5 <: FP5 + +type Node6 = NodeK { type FBound <: Bound6 } +type Bound6 <: FP6 +type FP6 = Fixed[Node6] From ebbc7936678c64a9196e9c193e49f1eadb308bb0 Mon Sep 17 00:00:00 2001 From: kasiaMarek Date: Tue, 21 Jan 2025 15:45:16 +0100 Subject: [PATCH 024/505] refactor: Use codeAction interface for most code actions [Cherry-picked 8d3c8ca1a717d82d6d60a564557fb4abdc756941] --- .../tools/pc/ScalaPresentationCompiler.scala | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala b/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala index 218d92c38ffa..f8480c0e9784 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala @@ -55,6 +55,14 @@ case class ScalaPresentationCompiler( completionItemPriority: CompletionItemPriority = (_: String) => 0, ) extends PresentationCompiler: + override def supportedCodeActions(): ju.List[String] = List( + CodeActionId.ConvertToNamedArguments, + CodeActionId.ImplementAbstractMembers, + CodeActionId.ExtractMethod, + CodeActionId.InlineValue, + CodeActionId.InsertInferredType + ).asJava + def this() = this("", None, Nil, Nil) val scalaVersion = BuildInfo.scalaVersion @@ -67,6 +75,42 @@ case class ScalaPresentationCompiler( .map(StdReportContext(_, _ => buildTargetName, reportsLevel)) .getOrElse(EmptyReportContext) + override def codeAction[T]( + params: OffsetParams, + codeActionId: String, + codeActionPayload: Optional[T] + ): CompletableFuture[ju.List[TextEdit]] = { + (codeActionId, codeActionPayload.asScala) match { + case ( + CodeActionId.ConvertToNamedArguments, + Some(argIndices: ju.List[_]) + ) => + val payload = argIndices.asScala.collect { case i: Integer => + i.toInt + }.toSet + convertToNamedArguments(params, payload) + case (CodeActionId.ImplementAbstractMembers, _) => + implementAbstractMembers(params) + case (CodeActionId.InsertInferredType, _) => + insertInferredType(params) + case (CodeActionId.InlineValue, _) => + inlineValue(params) + case (CodeActionId.ExtractMethod, Some(extractionPos: OffsetParams)) => + params match { + case range: RangeParams => + extractMethod(range, extractionPos) + case _ => + CompletableFuture.failedFuture( + new IllegalArgumentException(s"Expected range parameters") + ) + } + case (id, _) => + CompletableFuture.failedFuture( + new IllegalArgumentException(s"Unsupported action id $id") + ) + } + } + override def withCompletionItemPriority( priority: CompletionItemPriority ): PresentationCompiler = @@ -348,6 +392,12 @@ case class ScalaPresentationCompiler( override def convertToNamedArguments( params: OffsetParams, argIndices: ju.List[Integer] + ): CompletableFuture[ju.List[l.TextEdit]] = + convertToNamedArguments(params, argIndices.asScala.toSet.map(_.toInt)) + + def convertToNamedArguments( + params: OffsetParams, + argIndices: Set[Int] ): CompletableFuture[ju.List[l.TextEdit]] = val empty: Either[String, List[l.TextEdit]] = Right(List()) (compilerAccess @@ -355,7 +405,7 @@ case class ScalaPresentationCompiler( new ConvertToNamedArgumentsProvider( pc.compiler(), params, - argIndices.asScala.map(_.toInt).toSet + argIndices ).convertToNamedArguments }) .thenApplyAsync { From ac629bc78d8df24ccfd1fdaeb26a499a62185b34 Mon Sep 17 00:00:00 2001 From: kasiaMarek Date: Tue, 21 Jan 2025 15:47:13 +0100 Subject: [PATCH 025/505] Update ScalaPresentationCompiler.scala [Cherry-picked 31f5b4ed4faa570a43cdc0773b0d4642f56c3185] --- .../dotty/tools/pc/ScalaPresentationCompiler.scala | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala b/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala index f8480c0e9784..b3f8bba78953 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala @@ -79,15 +79,14 @@ case class ScalaPresentationCompiler( params: OffsetParams, codeActionId: String, codeActionPayload: Optional[T] - ): CompletableFuture[ju.List[TextEdit]] = { - (codeActionId, codeActionPayload.asScala) match { + ): CompletableFuture[ju.List[TextEdit]] = + (codeActionId, codeActionPayload.asScala) match case ( CodeActionId.ConvertToNamedArguments, Some(argIndices: ju.List[_]) ) => - val payload = argIndices.asScala.collect { case i: Integer => - i.toInt - }.toSet + val payload = + argIndices.asScala.collect { case i: Integer => i.toInt }.toSet convertToNamedArguments(params, payload) case (CodeActionId.ImplementAbstractMembers, _) => implementAbstractMembers(params) @@ -108,8 +107,6 @@ case class ScalaPresentationCompiler( CompletableFuture.failedFuture( new IllegalArgumentException(s"Unsupported action id $id") ) - } - } override def withCompletionItemPriority( priority: CompletionItemPriority From d193f734a2c3c5d48485701f948781ceb02b1492 Mon Sep 17 00:00:00 2001 From: kasiaMarek Date: Tue, 21 Jan 2025 16:11:10 +0100 Subject: [PATCH 026/505] bugfix: Show implicit chained calls in inlay hints [Cherry-picked a40b9999804393c85ee6e68d4d66e6a61dd68509] --- .../dotty/tools/pc/PcInlayHintsProvider.scala | 81 ++++++++++-- .../pc/tests/inlayHints/InlayHintsSuite.scala | 117 +++++++++++++++++- 2 files changed, 185 insertions(+), 13 deletions(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala index 9c0e6bcfa9d8..4b1b3f5fe7ba 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala @@ -80,15 +80,15 @@ class PcInlayHintsProvider( LabelPart(")") :: Nil, InlayHintKind.Parameter, ) - case ImplicitParameters(symbols, pos, allImplicit) => - val labelParts = symbols.map(s => List(labelPart(s, s.decodedName))) - val label = - if allImplicit then labelParts.separated("(using ", ", ", ")") - else labelParts.separated(", ") + case ImplicitParameters(trees, pos) => inlayHints.add( adjustPos(pos).toLsp, - label, - InlayHintKind.Parameter, + ImplicitParameters.partsFromImplicitArgs(trees).map((label, maybeSymbol) => + maybeSymbol match + case Some(symbol) => labelPart(symbol, label) + case None => LabelPart(label) + ), + InlayHintKind.Parameter ) case ValueOf(label, pos) => inlayHints.add( @@ -221,12 +221,8 @@ object ImplicitParameters: case Apply(fun, args) if args.exists(isSyntheticArg) && !tree.sourcePos.span.isZeroExtent && !args.exists(isQuotes(_)) => val (implicitArgs, providedArgs) = args.partition(isSyntheticArg) - val allImplicit = providedArgs.isEmpty || providedArgs.forall { - case Ident(name) => name == nme.MISSING - case _ => false - } val pos = implicitArgs.head.sourcePos - Some(implicitArgs.map(_.symbol), pos, allImplicit) + Some(implicitArgs, pos) case _ => None } else None @@ -242,6 +238,67 @@ object ImplicitParameters: private def isQuotes(tree: Tree)(using Context) = tree.tpe.typeSymbol == defn.QuotesClass + def partsFromImplicitArgs(trees: List[Tree])(using Context): List[(String, Option[Symbol])] = { + @tailrec + def recurseImplicitArgs( + currentArgs: List[Tree], + remainingArgsLists: List[List[Tree]], + parts: List[(String, Option[Symbol])] + ): List[(String, Option[Symbol])] = + (currentArgs, remainingArgsLists) match { + case (Nil, Nil) => parts + case (Nil, headArgsList :: tailArgsList) => + if (headArgsList.isEmpty) { + recurseImplicitArgs( + headArgsList, + tailArgsList, + (")", None) :: parts + ) + } else { + recurseImplicitArgs( + headArgsList, + tailArgsList, + (", ", None) :: (")", None) :: parts + ) + } + case (arg :: remainingArgs, remainingArgsLists) => + arg match { + case Apply(fun, args) => + val applyLabel = (fun.symbol.decodedName, Some(fun.symbol)) + recurseImplicitArgs( + args, + remainingArgs :: remainingArgsLists, + ("(", None) :: applyLabel :: parts + ) + case t if t.isTerm => + val termLabel = (t.symbol.decodedName, Some(t.symbol)) + if (remainingArgs.isEmpty) + recurseImplicitArgs( + remainingArgs, + remainingArgsLists, + termLabel :: parts + ) + else + recurseImplicitArgs( + remainingArgs, + remainingArgsLists, + (", ", None) :: termLabel :: parts + ) + case _ => + recurseImplicitArgs( + remainingArgs, + remainingArgsLists, + parts + ) + } + } + ((")", None) :: recurseImplicitArgs( + trees, + Nil, + List(("(using ", None)) + )).reverse + } + end ImplicitParameters object ValueOf: diff --git a/presentation-compiler/test/dotty/tools/pc/tests/inlayHints/InlayHintsSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/inlayHints/InlayHintsSuite.scala index ce9a89f313ef..8aa885149852 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/inlayHints/InlayHintsSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/inlayHints/InlayHintsSuite.scala @@ -937,7 +937,122 @@ class InlayHintsSuite extends BaseInlayHintsSuite { | given A = A() | implicit def bar(using a: A): B[A] = B[A]() | def foo(using b: B[A]): String = "aaa" - | val g: String = foo/*(using bar<<(5:15)>>)*/ + | val g: String = foo/*(using bar<<(5:15)>>(given_A<<(4:8)>>))*/ |""".stripMargin ) + + @Test def `multiple-params-list` = + check( + """|object Main { + | case class A() + | case class B() + | implicit val theA: A = A() + | def foo(b: B)(implicit a: A): String = "aaa" + | val g: String = foo(B()) + |} + |""".stripMargin, + """|object Main { + | case class A() + | case class B() + | implicit val theA: A = A() + | def foo(b: B)(implicit a: A): String = "aaa" + | val g: String = foo(B())/*(using theA<<(4:15)>>)*/ + |} + |""".stripMargin, + ) + + @Test def `implicit-chain` = + check( + """|object Main{ + | def hello()(implicit string: String, integer: Int, long: Long): String = { + | println(s"Hello $string, $long, $integer!") + | } + | implicit def theString(implicit i: Int): String = i.toString + | implicit def theInt(implicit l: Long): Int = l + | implicit val theLong: Long = 42 + | hello() + |} + |""".stripMargin, + """|object Main{ + | def hello()(implicit string: String, integer: Int, long: Long): String = { + | println(s"Hello $string, $long, $integer!") + | } + | implicit def theString(implicit i: Int): String = i.toString + | implicit def theInt(implicit l: Long): Int = l + | implicit val theLong: Long = 42 + | hello()/*(using theString<<(5:15)>>(theInt<<(6:15)>>(theLong<<(7:15)>>)), theInt<<(6:15)>>(theLong<<(7:15)>>), theLong<<(7:15)>>)*/ + |} + |""".stripMargin, + ) + + @Test def `implicit-parameterless-def` = + check( + """|object Main{ + | def hello()(implicit string: String, integer: Int, long: Long): String = { + | println(s"Hello $string, $long, $integer!") + | } + | implicit def theString(implicit i: Int): String = i.toString + | implicit def theInt: Int = 43 + | implicit def theLong: Long = 42 + | hello() + |} + |""".stripMargin, + """|object Main{ + | def hello()(implicit string: String, integer: Int, long: Long): String = { + | println(s"Hello $string, $long, $integer!") + | } + | implicit def theString(implicit i: Int): String = i.toString + | implicit def theInt: Int = 43 + | implicit def theLong: Long = 42 + | hello()/*(using theString<<(5:15)>>(theInt<<(6:15)>>), theInt<<(6:15)>>, theLong<<(7:15)>>)*/ + |} + |""".stripMargin, + ) + + @Test def `implicit-fn` = + check( + """|object Main{ + | implicit def stringLength(s: String): Int = s.length + | implicitly[String => Int] + | + | implicit val namedStringLength: String => Long = (s: String) => s.length.toLong + | implicitly[String => Long] + |} + |""".stripMargin, + """|object Main{ + | implicit def stringLength(s: String): Int = s.length + | implicitly[String => Int] + | + | implicit val namedStringLength: String => Long = (s: String) => s.length.toLong + | implicitly[String => Long]/*(using namedStringLength<<(5:15)>>)*/ + |} + |""".stripMargin, + ) + + @Test def `implicit-fn2` = + check( + """|object Main{ + | implicit def stringLength(s: String, i: Int): Int = s.length + | implicitly[(String, Int) => Int] + |} + |""".stripMargin, + """|object Main{ + | implicit def stringLength(s: String, i: Int): Int = s.length + | implicitly[(String, Int) => Int] + |} + |""".stripMargin, + ) + + @Test def `strip-margin` = + check( + """|object Main{ + | "".stripMargin + |} + |""".stripMargin, + """|package test + |object Main{ + | /*augmentString<>(*/""/*)*/.stripMargin + |} + |""".stripMargin + ) } From 3b85e8b4afc519ce2f0b1e0f35480557713f2251 Mon Sep 17 00:00:00 2001 From: kasiaMarek Date: Tue, 21 Jan 2025 16:32:43 +0100 Subject: [PATCH 027/505] improvement: Make including detail in completion label configurable [Cherry-picked eaa827eef7b15ad0bebc76f8dcb83b44a02b0102] --- .../pc/completions/CompletionProvider.scala | 4 +- .../CompletionWithoutDetailsSuite.scala | 120 ++++++++++++++++++ 2 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionWithoutDetailsSuite.scala diff --git a/presentation-compiler/src/main/dotty/tools/pc/completions/CompletionProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/completions/CompletionProvider.scala index adaeadb12978..28519debec63 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/completions/CompletionProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/completions/CompletionProvider.scala @@ -218,7 +218,9 @@ class CompletionProvider( // related issue https://github.com/lampepfl/scala3/issues/11941 lazy val kind: CompletionItemKind = underlyingCompletion.completionItemKind val description = underlyingCompletion.description(printer) - val label = underlyingCompletion.labelWithDescription(printer) + val label = + if config.isDetailIncludedInLabel then completion.labelWithDescription(printer) + else completion.label val ident = underlyingCompletion.insertText.getOrElse(underlyingCompletion.label) lazy val isInStringInterpolation = diff --git a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionWithoutDetailsSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionWithoutDetailsSuite.scala new file mode 100644 index 000000000000..f265b5393ccc --- /dev/null +++ b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionWithoutDetailsSuite.scala @@ -0,0 +1,120 @@ +package dotty.tools.pc.tests.completion + +import dotty.tools.pc.base.BaseCompletionSuite + +import scala.meta.internal.pc.PresentationCompilerConfigImpl +import scala.meta.pc.PresentationCompilerConfig + +import org.junit.Test + +class CompletionWithoutDetailsSuite extends BaseCompletionSuite: + + override def config: PresentationCompilerConfig = + PresentationCompilerConfigImpl().copy( + isDetailIncludedInLabel = false + ) + + @Test def `scope` = + check( + """ + |object A { + | Lis@@ + |}""".stripMargin, + """|List + |List + |List + |List + |ListUI + |""".stripMargin, + includeDetail = false, + topLines = Some(5) + ) + + @Test def `scope-detail` = + check( + """ + |object A { + | Lis@@ + |}""".stripMargin, + """|List[A](elems: A*): List[A] + |List scala.collection.immutable + |List java.awt + |List java.util + |ListUI javax.swing.plaf + |""".stripMargin, + includeDetail = true, + topLines = Some(5) + ) + + @Test def member = + check( + """ + |object A { + | List.emp@@ + |}""".stripMargin, + """ + |empty + |""".stripMargin, + includeDetail = false + ) + + @Test def extension = + check( + """ + |object A { + | "".stripSu@@ + |}""".stripMargin, + """|stripSuffix + |""".stripMargin, + includeDetail = false + ) + + @Test def tparam = + check( + """ + |class Foo[A] { + | def identity[B >: A](a: B): B = a + |} + |object Foo { + | new Foo[Int].ident@@ + |}""".stripMargin, + """|identity + |""".stripMargin, + includeDetail = false + ) + + @Test def tparam1 = + check( + """ + |class Foo[A] { + | def identity(a: A): A = a + |} + |object Foo { + | new Foo[Int].ident@@ + |}""".stripMargin, + """|identity + |""".stripMargin, + includeDetail = false + ) + + @Test def tparam2 = + check( + """ + |object A { + | Map.empty[Int, String].getOrEl@@ + |} + |""".stripMargin, + """|getOrElse + |""".stripMargin, + includeDetail = false + ) + + @Test def pkg = + check( + """ + |import scala.collection.conc@@ + |""".stripMargin, + """|concurrent + |""".stripMargin, + includeDetail = false + ) \ No newline at end of file From 91ceb8e23dec4f8e99d63ce2c2aec7932bfb615b Mon Sep 17 00:00:00 2001 From: kasiaMarek Date: Tue, 21 Jan 2025 16:39:01 +0100 Subject: [PATCH 028/505] fix: deduplicate scaladoc [Cherry-picked 7e50b1efc8f316cfbcac6609a56aec300bc88ce3] --- .../src/main/dotty/tools/pc/CompletionItemResolver.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/CompletionItemResolver.scala b/presentation-compiler/src/main/dotty/tools/pc/CompletionItemResolver.scala index 291ffe1fec30..ffd7377c8181 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/CompletionItemResolver.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/CompletionItemResolver.scala @@ -75,7 +75,7 @@ object CompletionItemResolver extends ItemResolver: else gsymDoc else val companionDoc = docs(companion) - if companionDoc.isEmpty() then gsymDoc + if companionDoc.isEmpty() || companionDoc == gsymDoc then gsymDoc else if gsymDoc.isEmpty() then companionDoc else List( From 583a4c6fd0e32be26050f3dc18d82992f1810d91 Mon Sep 17 00:00:00 2001 From: kasiaMarek Date: Tue, 21 Jan 2025 16:48:34 +0100 Subject: [PATCH 029/505] fix: don't look for overshadow conflicts for symbols not in the scope [Cherry-picked 6187ac02a23e1fb848dbbd0518e4e87681e583b8] --- .../tools/pc/PcInlineValueProviderImpl.scala | 23 +++---- .../pc/tests/edit/InlineValueSuite.scala | 61 +++++++++++++++++++ 2 files changed, 73 insertions(+), 11 deletions(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/PcInlineValueProviderImpl.scala b/presentation-compiler/src/main/dotty/tools/pc/PcInlineValueProviderImpl.scala index bbba44d0d84f..fc4b53e60bbd 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/PcInlineValueProviderImpl.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/PcInlineValueProviderImpl.scala @@ -18,6 +18,7 @@ import dotty.tools.dotc.interactive.Interactive import dotty.tools.dotc.interactive.InteractiveDriver import dotty.tools.dotc.util.SourcePosition import dotty.tools.pc.utils.InteractiveEnrichments.* +import dotty.tools.pc.IndexedContext.Result import org.eclipse.lsp4j as l @@ -49,7 +50,9 @@ final class PcInlineValueProviderImpl( DefinitionTree(defn, pos) } .toRight(Errors.didNotFindDefinition) - symbols = symbolsUsedInDefn(definition.tree.rhs) + path = Interactive.pathTo(unit.tpdTree, definition.tree.rhs.span)(using newctx) + indexedContext = IndexedContext(Interactive.contextOfPath(path)(using newctx)) + symbols = symbolsUsedInDefn(definition.tree.rhs).filter(indexedContext.lookupSym(_) == Result.InScope) references <- getReferencesToInline(definition, allOccurences, symbols) yield val (deleteDefinition, refsEdits) = references @@ -111,27 +114,25 @@ final class PcInlineValueProviderImpl( val adjustedEnd = extend(pos.end - 1, ')', 1) + 1 text.slice(adjustedStart, adjustedEnd).mkString - private def symbolsUsedInDefn( - rhs: Tree - ): List[Symbol] = + private def symbolsUsedInDefn(rhs: Tree): Set[Symbol] = def collectNames( - symbols: List[Symbol], + symbols: Set[Symbol], tree: Tree - ): List[Symbol] = + ): Set[Symbol] = tree match case id: (Ident | Select) if !id.symbol.is(Synthetic) && !id.symbol.is(Implicit) => - tree.symbol :: symbols + symbols + tree.symbol case _ => symbols - val traverser = new DeepFolder[List[Symbol]](collectNames) - traverser(List(), rhs) + val traverser = new DeepFolder[Set[Symbol]](collectNames) + traverser(Set(), rhs) end symbolsUsedInDefn private def getReferencesToInline( definition: DefinitionTree, allOccurences: List[Occurence], - symbols: List[Symbol] + symbols: Set[Symbol] ): Either[String, (Boolean, List[Reference])] = val defIsLocal = definition.tree.symbol.ownersIterator .drop(1) @@ -156,7 +157,7 @@ final class PcInlineValueProviderImpl( private def makeRefsEdits( refs: List[Occurence], - symbols: List[Symbol] + symbols: Set[Symbol] ): Either[String, List[Reference]] = val newctx = driver.currentCtx.fresh.setCompilationUnit(unit) def buildRef(occurrence: Occurence): Either[String, Reference] = diff --git a/presentation-compiler/test/dotty/tools/pc/tests/edit/InlineValueSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/edit/InlineValueSuite.scala index 0cec3952a7ef..cee0aada9f86 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/edit/InlineValueSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/edit/InlineValueSuite.scala @@ -301,6 +301,47 @@ class InlineValueSuite extends BaseCodeActionSuite with CommonMtagsEnrichments: |}""".stripMargin ) + + @Test def `i6924` = + checkEdit( + """|object O { + | def test(n: Int) = { + | val isOne = n == 1 + | <>sOne + | } + |} + |""".stripMargin, + """|object O { + | def test(n: Int) = { + | n == 1 + | } + |} + |""".stripMargin + ) + + @Test def `i6924-2` = + checkEdit( + """|object O { + | def ==(o: O) = false + |} + |object P { + | def test() = { + | val isOne = O == O + | <>sOne + | } + |} + |""".stripMargin, + """|object O { + | def ==(o: O) = false + |} + |object P { + | def test() = { + | O == O + | } + |} + |""".stripMargin + ) + @Test def `scoping-packages` = checkError( """|package a @@ -346,6 +387,26 @@ class InlineValueSuite extends BaseCodeActionSuite with CommonMtagsEnrichments: InlineErrors.variablesAreShadowed("A.k") ) + @Test def `bad-scoping-3` = + checkError( + """|class T { + | val a = 1 + |} + | + |class O { + | val t = new T() + | import t._ + | val bb = a + a + | + | class Inner { + | val a = 123 + | val cc = <>b + | } + |} + |""".stripMargin, + InlineErrors.variablesAreShadowed("T.a") + ) + def checkEdit( original: String, expected: String, From 0a6b8a464e18664275277852cdb12ba04bd0ff8f Mon Sep 17 00:00:00 2001 From: kasiaMarek Date: Tue, 21 Jan 2025 16:58:50 +0100 Subject: [PATCH 030/505] fix: don't show incorrect docs for inner methods [Cherry-picked 9a028cdca1a4b0e35f698f1e53db50d32bd31953] --- .../tools/pc/utils/InteractiveEnrichments.scala | 15 ++++++++++----- .../tools/pc/tests/hover/HoverDocSuite.scala | 12 ++++++++++++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/utils/InteractiveEnrichments.scala b/presentation-compiler/src/main/dotty/tools/pc/utils/InteractiveEnrichments.scala index 66080a363d51..b65f23fae40f 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/utils/InteractiveEnrichments.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/utils/InteractiveEnrichments.scala @@ -1,5 +1,7 @@ package dotty.tools.pc.utils +import java.util.Optional + import scala.annotation.tailrec import scala.meta.internal.jdk.CollectionConverters.* import scala.meta.internal.mtags.CommonMtagsEnrichments @@ -272,11 +274,14 @@ object InteractiveEnrichments extends CommonMtagsEnrichments: symbol.maybeOwner.companion, ).filter(_ != NoSymbol) ++ symbol.allOverriddenSymbols else symbol.allOverriddenSymbols - val documentation = search.documentation( - sym, - () => parentSymbols.iterator.map(toSemanticdbSymbol).toList.asJava, - contentType, - ) + val documentation = + if symbol.isLocal then Optional.empty + else + search.documentation( + sym, + () => parentSymbols.iterator.map(toSemanticdbSymbol).toList.asJava, + contentType, + ) documentation.nn.toScala end symbolDocumentation end extension diff --git a/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverDocSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverDocSuite.scala index fc9b6835e319..a82fa73865c8 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverDocSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverDocSuite.scala @@ -254,3 +254,15 @@ class HoverDocSuite extends BaseHoverSuite: |Found documentation for _empty_/Alpha# |""".stripMargin, ) + + @Test def `i7093` = + check( + """|object O: + | /** Ooopsie daisy */ + | val computeLogicOwners: Unit = + | /** This is a comment */ + | <> + | ??? + |""".stripMargin, + """def logicOwners: Nothing""".hover.stripMargin + ) From 174b497edc9553bfc08ad0558289d54411ceba8e Mon Sep 17 00:00:00 2001 From: kasiaMarek Date: Wed, 22 Jan 2025 11:54:25 +0100 Subject: [PATCH 031/505] adjust for Java 8 and fix doc test [Cherry-picked d1a150af4873dcccaccc6e3f3cd7b901071fc3b2] --- .../tools/pc/ScalaPresentationCompiler.scala | 15 +++++++-------- .../tools/pc/tests/hover/HoverNamedArgSuite.scala | 1 - 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala b/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala index b3f8bba78953..a44c16ecc748 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala @@ -98,15 +98,14 @@ case class ScalaPresentationCompiler( params match { case range: RangeParams => extractMethod(range, extractionPos) - case _ => - CompletableFuture.failedFuture( - new IllegalArgumentException(s"Expected range parameters") - ) + case _ => failedFuture(new IllegalArgumentException(s"Expected range parameters")) } - case (id, _) => - CompletableFuture.failedFuture( - new IllegalArgumentException(s"Unsupported action id $id") - ) + case (id, _) => failedFuture(new IllegalArgumentException(s"Unsupported action id $id")) + + private def failedFuture[T](e: Throwable): CompletableFuture[T] = + val f = new CompletableFuture[T]() + f.completeExceptionally(e) + f override def withCompletionItemPriority( priority: CompletionItemPriority diff --git a/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverNamedArgSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverNamedArgSuite.scala index 182f8e1e0644..9f9e11725447 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverNamedArgSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverNamedArgSuite.scala @@ -29,7 +29,6 @@ class HoverNamedArgSuite extends BaseHoverSuite: """|```scala |named: Int |``` - |Found documentation for a/b.foo().(named) |""".stripMargin ) From 2b87171968eb49263c74f13de8188ca31e4005d4 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Wed, 22 Jan 2025 07:46:29 -0800 Subject: [PATCH 032/505] Filter help renders box border [Cherry-picked e1bdfad9d1a47d54f038bce0928101bf43a57a9a] --- .../tools/dotc/reporting/MessageRendering.scala | 13 +++++++------ tests/neg/nowarn.check | 6 +++--- tests/warn/deprecated-origin-verbose.check | 12 ++++++------ tests/warn/i22412.check | 10 ++++++++++ tests/warn/i22412.scala | 3 +++ 5 files changed, 29 insertions(+), 15 deletions(-) create mode 100644 tests/warn/i22412.check create mode 100644 tests/warn/i22412.scala diff --git a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala index 7db5112b6674..45caf480f65e 100644 --- a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala +++ b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala @@ -209,20 +209,21 @@ trait MessageRendering { sb.toString } - private def appendFilterHelp(dia: Diagnostic, sb: StringBuilder): Unit = + private def appendFilterHelp(dia: Diagnostic, sb: StringBuilder)(using Context, Level, Offset): Unit = + extension (sb: StringBuilder) def nl: sb.type = sb.append(EOL).append(offsetBox) import dia.msg val hasId = msg.errorId.errorNumber >= 0 val (category, origin) = dia match - case _: UncheckedWarning => ("unchecked", "") + case _: UncheckedWarning => ("unchecked", "") case w: DeprecationWarning => ("deprecation", w.origin) - case _: FeatureWarning => ("feature", "") - case _ => ("", "") + case _: FeatureWarning => ("feature", "") + case _ => ("", "") var entitled = false def addHelp(what: String)(value: String): Unit = if !entitled then - sb.append(EOL).append("Matching filters for @nowarn or -Wconf:") + sb.nl.append("Matching filters for @nowarn or -Wconf:") entitled = true - sb.append(EOL).append(" - ").append(what).append(value) + sb.nl.append(" - ").append(what).append(value) if hasId then addHelp("id=E")(msg.errorId.errorNumber.toString) addHelp("name=")(msg.errorId.productPrefix.stripSuffix("ID")) diff --git a/tests/neg/nowarn.check b/tests/neg/nowarn.check index 636cabd44d07..ff01de1788bd 100644 --- a/tests/neg/nowarn.check +++ b/tests/neg/nowarn.check @@ -24,9 +24,9 @@ | ^^^^^ | A try without catch or finally is equivalent to putting | its body in a block; no exceptions are handled. -Matching filters for @nowarn or -Wconf: - - id=E2 - - name=EmptyCatchAndFinallyBlock + |Matching filters for @nowarn or -Wconf: + | - id=E2 + | - name=EmptyCatchAndFinallyBlock | | longer explanation available when compiling with `-explain` -- [E129] Potential Issue Warning: tests/neg/nowarn.scala:15:11 -------------------------------------------------------- diff --git a/tests/warn/deprecated-origin-verbose.check b/tests/warn/deprecated-origin-verbose.check index e67efaf8668d..db0ee26fd779 100644 --- a/tests/warn/deprecated-origin-verbose.check +++ b/tests/warn/deprecated-origin-verbose.check @@ -2,13 +2,13 @@ 12 | class D extends C // warn | ^ | class C in package p is deprecated since 1.0: Old style -Matching filters for @nowarn or -Wconf: - - cat=deprecation - - origin=p.C + |Matching filters for @nowarn or -Wconf: + | - cat=deprecation + | - origin=p.C -- Deprecation Warning: tests/warn/deprecated-origin-verbose.scala:13:20 ----------------------------------------------- 13 | class Oil extends Crude // warn | ^^^^^ | class Crude in package p is deprecated since 1.0: Bad style -Matching filters for @nowarn or -Wconf: - - cat=deprecation - - origin=p.Crude + |Matching filters for @nowarn or -Wconf: + | - cat=deprecation + | - origin=p.Crude diff --git a/tests/warn/i22412.check b/tests/warn/i22412.check new file mode 100644 index 000000000000..adbe698db058 --- /dev/null +++ b/tests/warn/i22412.check @@ -0,0 +1,10 @@ +-- [E002] Syntax Warning: tests/warn/i22412.scala:3:34 ----------------------------------------------------------------- +3 | @annotation.nowarn("v") def f = try 1 // warn + | ^^^^^ + | A try without catch or finally is equivalent to putting + | its body in a block; no exceptions are handled. + |Matching filters for @nowarn or -Wconf: + | - id=E2 + | - name=EmptyCatchAndFinallyBlock + | + | longer explanation available when compiling with `-explain` diff --git a/tests/warn/i22412.scala b/tests/warn/i22412.scala new file mode 100644 index 000000000000..870a264c1df1 --- /dev/null +++ b/tests/warn/i22412.scala @@ -0,0 +1,3 @@ + +class C: + @annotation.nowarn("v") def f = try 1 // warn From 42a56678057dc29f5e8dac7ba9d151b1b7ce410c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Fri, 17 Jan 2025 17:04:40 +0100 Subject: [PATCH 033/505] Scala.js: Emit `js.NewArray` IR nodes when possible. Although there is a *correct* implementation of `sr.Arrays.newArray`, it is not efficient when creating 1-dimensional arrays. The JVM backend special-cases it to emit `newarray` bytecode instructions. We now also special-case it in the JS backend. In the Scala.js IR however, `js.NewArray` only accepts a single dimension. For multiple dimensions, the right thing to do is to emit a direct call to `jlr.Array.newInstance`. [Cherry-picked 2852168e8ddac8aa318635a73c79f64282aa39d1] --- .../dotty/tools/backend/sjs/JSCodeGen.scala | 24 +++++++++++++++++++ .../tools/backend/sjs/JSPrimitives.scala | 6 +++-- .../src/dotty/tools/dotc/core/Types.scala | 8 ++++--- .../pc/utils/InteractiveEnrichments.scala | 2 +- 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala index 1572ed476c6c..9e5743147122 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala @@ -2553,6 +2553,8 @@ class JSCodeGen()(using genCtx: Context) { genCoercion(tree, receiver, code) else if (code == JSPrimitives.THROW) genThrow(tree, args) + else if (code == JSPrimitives.NEW_ARRAY) + genNewArray(tree, args) else if (JSPrimitives.isJSPrimitive(code)) genJSPrimitive(tree, args, code, isStat) else @@ -3022,6 +3024,24 @@ class JSCodeGen()(using genCtx: Context) { } } + /** Gen a call to the special `newArray` method. */ + private def genNewArray(tree: Apply, args: List[Tree]): js.Tree = { + implicit val pos: SourcePosition = tree.sourcePos + + val List(elemClazz, Literal(arrayClassConstant), dimsArray: JavaSeqLiteral) = args: @unchecked + + dimsArray.elems match { + case singleDim :: Nil => + // Use a js.NewArray + val arrayTypeRef = toTypeRef(arrayClassConstant.typeValue).asInstanceOf[jstpe.ArrayTypeRef] + js.NewArray(arrayTypeRef, List(genExpr(singleDim))) + case _ => + // Delegate to jlr.Array.newInstance + js.ApplyStatic(js.ApplyFlags.empty, JLRArrayClassName, js.MethodIdent(JLRArrayNewInstanceMethodName), + List(genExpr(elemClazz), genJavaSeqLiteral(dimsArray)))(jstpe.AnyType) + } + } + /** Gen a "normal" apply (to a true method). * * But even these are further refined into: @@ -4835,6 +4855,7 @@ class JSCodeGen()(using genCtx: Context) { object JSCodeGen { private val NullPointerExceptionClass = ClassName("java.lang.NullPointerException") + private val JLRArrayClassName = ClassName("java.lang.reflect.Array") private val JSObjectClassName = ClassName("scala.scalajs.js.Object") private val JavaScriptExceptionClassName = ClassName("scala.scalajs.js.JavaScriptException") @@ -4844,6 +4865,9 @@ object JSCodeGen { private val selectedValueMethodName = MethodName("selectedValue", Nil, ObjectClassRef) + private val JLRArrayNewInstanceMethodName = + MethodName("newInstance", List(jstpe.ClassRef(jsNames.ClassClass), jstpe.ArrayTypeRef(jstpe.IntRef, 1)), ObjectClassRef) + private val ObjectArgConstructorName = MethodName.constructor(List(ObjectClassRef)) private val thisOriginalName = OriginalName("this") diff --git a/compiler/src/dotty/tools/backend/sjs/JSPrimitives.scala b/compiler/src/dotty/tools/backend/sjs/JSPrimitives.scala index a3a37795826a..f23c816b5204 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSPrimitives.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSPrimitives.scala @@ -48,9 +48,10 @@ object JSPrimitives { inline val UNWRAP_FROM_THROWABLE = WRAP_AS_THROWABLE + 1 // js.special.unwrapFromThrowable inline val DEBUGGER = UNWRAP_FROM_THROWABLE + 1 // js.special.debugger - inline val THROW = DEBUGGER + 1 + inline val THROW = DEBUGGER + 1 // .throw + inline val NEW_ARRAY = THROW + 1 // scala.runtime.Arrays.newArray - inline val UNION_FROM = THROW + 1 // js.|.from + inline val UNION_FROM = NEW_ARRAY + 1 // js.|.from inline val UNION_FROM_TYPE_CONSTRUCTOR = UNION_FROM + 1 // js.|.fromTypeConstructor inline val REFLECT_SELECTABLE_SELECTDYN = UNION_FROM_TYPE_CONSTRUCTOR + 1 // scala.reflect.Selectable.selectDynamic @@ -137,6 +138,7 @@ class JSPrimitives(ictx: Context) extends DottyPrimitives(ictx) { addPrimitive(jsdefn.Special_debugger, DEBUGGER) addPrimitive(defn.throwMethod, THROW) + addPrimitive(defn.newArrayMethod, NEW_ARRAY) addPrimitive(jsdefn.PseudoUnion_from, UNION_FROM) addPrimitive(jsdefn.PseudoUnion_fromTypeConstructor, UNION_FROM_TYPE_CONSTRUCTOR) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index ac6089516571..1113f7413e6e 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -5794,11 +5794,13 @@ object Types extends TypeUtils { protected def derivedLambdaType(tp: LambdaType)(formals: List[tp.PInfo], restpe: Type): Type = tp.derivedLambdaType(tp.paramNames, formals, restpe) + protected def mapArg(arg: Type, tparam: ParamInfo): Type = arg match + case arg: TypeBounds => this(arg) + case arg => atVariance(variance * tparam.paramVarianceSign)(this(arg)) + protected def mapArgs(args: List[Type], tparams: List[ParamInfo]): List[Type] = args match case arg :: otherArgs if tparams.nonEmpty => - val arg1 = arg match - case arg: TypeBounds => this(arg) - case arg => atVariance(variance * tparams.head.paramVarianceSign)(this(arg)) + val arg1 = mapArg(arg, tparams.head) val otherArgs1 = mapArgs(otherArgs, tparams.tail) if ((arg1 eq arg) && (otherArgs1 eq otherArgs)) args else arg1 :: otherArgs1 diff --git a/presentation-compiler/src/main/dotty/tools/pc/utils/InteractiveEnrichments.scala b/presentation-compiler/src/main/dotty/tools/pc/utils/InteractiveEnrichments.scala index b65f23fae40f..d909b6ee7e04 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/utils/InteractiveEnrichments.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/utils/InteractiveEnrichments.scala @@ -281,7 +281,7 @@ object InteractiveEnrichments extends CommonMtagsEnrichments: sym, () => parentSymbols.iterator.map(toSemanticdbSymbol).toList.asJava, contentType, - ) + ).nn documentation.nn.toScala end symbolDocumentation end extension From a76ababad00cec70ae1199992e0a306e74654e0b Mon Sep 17 00:00:00 2001 From: Jan Chyb <48855024+jchyb@users.noreply.github.com> Date: Thu, 30 Jan 2025 11:53:37 +0100 Subject: [PATCH 034/505] Fix stack overflow errors when generating opaque type proxies (#22479) Before the regressive PR, we would check via the generated opaqueProxies list whether one was already generated. In that PR, we tried allowing generating proxies for rhs of currently generated proxy. Since we have to add the generated proxy to opaqueProxies only after that step, this could cause infinite recursion (and adding the proxies earlier could cause another infinite loop). To fix that, we add another collection for termrefs which we already visited this way, but which is not used in the `mapOpaques` function. [Cherry-picked 6d9b0f14f18b89d1719fd5346284eae9cc6e39bc] --- compiler/src/dotty/tools/dotc/inlines/Inliner.scala | 6 +++++- tests/pos/i22468.scala | 10 ++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 tests/pos/i22468.scala diff --git a/compiler/src/dotty/tools/dotc/inlines/Inliner.scala b/compiler/src/dotty/tools/dotc/inlines/Inliner.scala index 5a8111a4cc28..7e9e4498e310 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inliner.scala @@ -384,6 +384,9 @@ class Inliner(val call: tpd.Tree)(using Context): */ private val opaqueProxies = new mutable.ListBuffer[(TermRef, TermRef)] + /** TermRefs for which we already started synthesising proxies */ + private val visitedTermRefs = new mutable.HashSet[TermRef] + protected def hasOpaqueProxies = opaqueProxies.nonEmpty /** Map first halves of opaqueProxies pairs to second halves, using =:= as equality */ @@ -401,8 +404,9 @@ class Inliner(val call: tpd.Tree)(using Context): for cls <- ref.widen.baseClasses do if cls.containsOpaques && (forThisProxy || inlinedMethod.isContainedIn(cls)) - && mapRef(ref).isEmpty + && !visitedTermRefs.contains(ref) then + visitedTermRefs += ref val refiningRef = OpaqueProxy(ref, cls, call.span) val refiningSym = refiningRef.symbol.asTerm val refinedType = refiningRef.info diff --git a/tests/pos/i22468.scala b/tests/pos/i22468.scala new file mode 100644 index 000000000000..265d6d3a89b7 --- /dev/null +++ b/tests/pos/i22468.scala @@ -0,0 +1,10 @@ +import Result.* +opaque type Result[+E, +A] = Success[A] | Error[E] + +object Result: + opaque type Success[+A] = A + sealed abstract class Error[+E] + + extension [E, A](self: Result[E, A]) + inline def transform[B]: B = ??? + def problem: Boolean = transform[Boolean] From 08a0f29944e7ebe2f0a4c89c5644d4077006cd62 Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Thu, 30 Jan 2025 14:35:10 +0100 Subject: [PATCH 035/505] fix: record calls to constructors in lambdaLift [Cherry-picked 5dddf7e0f7ffd5835754bd2ceedba363b15b6e0c] --- .../tools/dotc/transform/Dependencies.scala | 6 ++++- .../tools/dotc/transform/LambdaLift.scala | 4 +-- tests/pos/i21931.scala | 25 +++++++++++-------- tests/pos/i22470.scala | 17 +++++++++++++ 4 files changed, 38 insertions(+), 14 deletions(-) create mode 100644 tests/pos/i22470.scala diff --git a/compiler/src/dotty/tools/dotc/transform/Dependencies.scala b/compiler/src/dotty/tools/dotc/transform/Dependencies.scala index 28fd21200759..ad40141fad43 100644 --- a/compiler/src/dotty/tools/dotc/transform/Dependencies.scala +++ b/compiler/src/dotty/tools/dotc/transform/Dependencies.scala @@ -136,6 +136,7 @@ abstract class Dependencies(root: ast.tpd.Tree, @constructorOnly rootContext: Co if !enclosure.exists then throw NoPath() if enclosure == sym.enclosure then NoSymbol else + /** is sym a constructor or a term that is nested in a constructor? */ def nestedInConstructor(sym: Symbol): Boolean = sym.isConstructor || sym.isTerm && nestedInConstructor(sym.enclosure) @@ -236,6 +237,10 @@ abstract class Dependencies(root: ast.tpd.Tree, @constructorOnly rootContext: Co captureImplicitThis(tree.tpe) case tree: Select => if isExpr(sym) && isLocal(sym) then markCalled(sym, enclosure) + case tree: New => + val constr = tree.tpe.typeSymbol.primaryConstructor + if isExpr(constr) then + symSet(called, enclosure) += constr case tree: This => narrowTo(tree.symbol.asClass) case tree: MemberDef if isExpr(sym) && sym.owner.isTerm => @@ -290,7 +295,6 @@ abstract class Dependencies(root: ast.tpd.Tree, @constructorOnly rootContext: Co val calleeOwner = normalizedCallee.owner if calleeOwner.isTerm then narrowLogicOwner(caller, logicOwner(normalizedCallee)) else - assert(calleeOwner.is(Trait)) // methods nested inside local trait methods cannot be lifted out // beyond the trait. Note that we can also call a trait method through // a qualifier; in that case no restriction to lifted owner arises. diff --git a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala index 6a7dee2ff4fe..3fbdf1fa5427 100644 --- a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala +++ b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala @@ -127,9 +127,7 @@ object LambdaLift: private def proxy(sym: Symbol)(using Context): Symbol = { def liftedEnclosure(sym: Symbol) = - if sym.is(Method) - then deps.logicalOwner.getOrElse(sym, sym.enclosure) - else sym.enclosure + deps.logicalOwner.getOrElse(sym, sym.enclosure) def searchIn(enclosure: Symbol): Symbol = { if (!enclosure.exists) { def enclosures(encl: Symbol): List[Symbol] = diff --git a/tests/pos/i21931.scala b/tests/pos/i21931.scala index 6765768874af..d4deb93f4c2e 100644 --- a/tests/pos/i21931.scala +++ b/tests/pos/i21931.scala @@ -1,13 +1,18 @@ -def f() = - val NotFound: Char = 'a' - class crashing() { - class issue() { - NotFound - } - class Module() { - val obligatory = - class anonIssue() { - issue() +object Test { + def f() = { + val NotFound: Char = 'a' + class crashing() { + class issue() { + NotFound + } + class Module() { + val obligatory = { + def anonIssue = { + issue() + } + anonIssue } + } } } +} diff --git a/tests/pos/i22470.scala b/tests/pos/i22470.scala new file mode 100644 index 000000000000..83599f2564fc --- /dev/null +++ b/tests/pos/i22470.scala @@ -0,0 +1,17 @@ +trait A +trait OuterClass +trait MidClass +trait InnerClass + +object Obj: + def outerDef(a: A) = + new OuterClass { + def midDef(): Unit = { + new MidClass { + val valdef = new InnerClass { + def innerDef() = + println(a) + } + } + } + } From 64fb8d6fedaddbbda414dfefb4c613af0cf5b31d Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Tue, 18 Feb 2025 13:08:57 +0100 Subject: [PATCH 036/505] Review fixes [Cherry-picked 51c5c41227ae7d70d6fd7b5dde20336e73288e0e] --- compiler/src/dotty/tools/dotc/transform/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/transform/Dependencies.scala b/compiler/src/dotty/tools/dotc/transform/Dependencies.scala index ad40141fad43..5d76158edc96 100644 --- a/compiler/src/dotty/tools/dotc/transform/Dependencies.scala +++ b/compiler/src/dotty/tools/dotc/transform/Dependencies.scala @@ -239,7 +239,7 @@ abstract class Dependencies(root: ast.tpd.Tree, @constructorOnly rootContext: Co if isExpr(sym) && isLocal(sym) then markCalled(sym, enclosure) case tree: New => val constr = tree.tpe.typeSymbol.primaryConstructor - if isExpr(constr) then + if constr.exists then symSet(called, enclosure) += constr case tree: This => narrowTo(tree.symbol.asClass) From b6462388fbdbc03bb659cb697b76b9b6bef4f030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Thu, 13 Mar 2025 17:05:16 +0100 Subject: [PATCH 037/505] Fix #22794: Emit the definition of `Arrays.newArray` even though it's a primitive. Until 3.6.x, we used the user-space definition of `Arrays.newArray` in Scala.js. We changed it to a primitve in 2852168e8ddac8aa318635a73c79f64282aa39d1, to match the behavior of the JVM backend. However, that had the side effect of not emitting its definition at all, like other primitives. For backward binary compat reasons, we do need that definition. We specifically make an exception for that method, which is now emitted, even though it is otherwise treated as a primitive. [Cherry-picked 9c7193a2889b139e2cdbee2e4ea06cf82428e404] --- compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala | 2 +- sbt-test/scalajs/backward-compat/build.sbt | 5 +++++ sbt-test/scalajs/backward-compat/project/plugins.sbt | 2 ++ .../src/test/scala/NewArrayIssue22794Test.scala | 5 +++++ sbt-test/scalajs/backward-compat/test | 1 + 5 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 sbt-test/scalajs/backward-compat/build.sbt create mode 100644 sbt-test/scalajs/backward-compat/project/plugins.sbt create mode 100644 sbt-test/scalajs/backward-compat/src/test/scala/NewArrayIssue22794Test.scala create mode 100644 sbt-test/scalajs/backward-compat/test diff --git a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala index 9e5743147122..4e63d31b6842 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala @@ -1496,7 +1496,7 @@ class JSCodeGen()(using genCtx: Context) { def jsParams = params.map(genParamDef(_)) - if (primitives.isPrimitive(sym)) { + if (primitives.isPrimitive(sym) && sym != defn.newArrayMethod) { None } else if (sym.is(Deferred) && currentClassSym.isNonNativeJSClass) { // scala-js/#4409: Do not emit abstract methods in non-native JS classes diff --git a/sbt-test/scalajs/backward-compat/build.sbt b/sbt-test/scalajs/backward-compat/build.sbt new file mode 100644 index 000000000000..552452b72f6f --- /dev/null +++ b/sbt-test/scalajs/backward-compat/build.sbt @@ -0,0 +1,5 @@ +enablePlugins(ScalaJSPlugin) + +scalaVersion := sys.props("plugin.scalaVersion") + +libraryDependencies += "org.scalameta" %%% "munit" % "1.0.0-M10" diff --git a/sbt-test/scalajs/backward-compat/project/plugins.sbt b/sbt-test/scalajs/backward-compat/project/plugins.sbt new file mode 100644 index 000000000000..b30c6e8c5ec8 --- /dev/null +++ b/sbt-test/scalajs/backward-compat/project/plugins.sbt @@ -0,0 +1,2 @@ + +addSbtPlugin("org.scala-js" % "sbt-scalajs" % sys.props("plugin.scalaJSVersion")) diff --git a/sbt-test/scalajs/backward-compat/src/test/scala/NewArrayIssue22794Test.scala b/sbt-test/scalajs/backward-compat/src/test/scala/NewArrayIssue22794Test.scala new file mode 100644 index 000000000000..0385b537bfe4 --- /dev/null +++ b/sbt-test/scalajs/backward-compat/src/test/scala/NewArrayIssue22794Test.scala @@ -0,0 +1,5 @@ +class NewArrayIssue22794Test extends munit.FunSuite { + test("foo") { + assert(2 + 2 == 4) + } +} diff --git a/sbt-test/scalajs/backward-compat/test b/sbt-test/scalajs/backward-compat/test new file mode 100644 index 000000000000..dfffb838b4b3 --- /dev/null +++ b/sbt-test/scalajs/backward-compat/test @@ -0,0 +1 @@ +> test From 76e7558421c24ca35d0cb36c4c54e9a679d2f280 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Fri, 28 Jun 2024 17:26:23 -0700 Subject: [PATCH 038/505] Respect prefix when checking if selector selects Use miniphase api instead of traversing. Share a megaphase with CheckShadowing. Perform more expensive checks last. Avoid intermediate collections. Tighten allowance for serialization methods. Don't ignore params of public methods. Show misplaced warn comment, unfulfilled expectations. Warn for unused patvars. Don't warn about canonical names (case class element names). Warn unassigned mutable patvars No transparent inline exclusion. Handle match types. No warn inline proxy. Detect summon inline. Unused import diagnostics have an origin. Original of literal. Typos in build. Handle aliased boolean settings. Resolve imports post inlining. Excuse only empty interfaces as unused bound. Use result of TypeTest. --- .../tools/backend/jvm/BCodeSkelBuilder.scala | 6 +- compiler/src/dotty/tools/dotc/Compiler.scala | 6 +- .../src/dotty/tools/dotc/ast/Desugar.scala | 14 +- .../tools/dotc/config/ScalaSettings.scala | 20 +- .../dotty/tools/dotc/core/Definitions.scala | 5 + compiler/src/dotty/tools/dotc/report.scala | 15 +- .../tools/dotc/reporting/Diagnostic.scala | 22 +- .../dotty/tools/dotc/reporting/WConf.scala | 24 +- .../dotty/tools/dotc/reporting/messages.scala | 25 +- .../tools/dotc/transform/CheckShadowing.scala | 40 +- .../tools/dotc/transform/CheckUnused.scala | 1656 +++++++++-------- .../tools/dotc/transform/PostTyper.scala | 4 +- .../src/dotty/tools/dotc/typer/Deriving.scala | 25 +- .../src/dotty/tools/dotc/typer/Typer.scala | 9 +- .../src/dotty/tools/dotc/util/chaining.scala | 8 + .../src/dotty/tools/repl/ReplCompiler.scala | 3 +- .../dotty/tools/dotc/CompilationTests.scala | 1 + .../dotty/tools/vulpix/ParallelTesting.scala | 70 +- library/src/scala/deriving/Mirror.scala | 2 +- library/src/scala/quoted/Quotes.scala | 7 +- library/src/scala/runtime/Arrays.scala | 3 +- project/Build.scala | 8 +- tasty/src/dotty/tools/tasty/TastyReader.scala | 2 +- tests/pos/i11729.scala | 4 +- tests/pos/i17631.scala | 22 +- tests/pos/i18366.scala | 10 - tests/pos/i3323.scala | 9 - tests/pos/tuple-exaustivity.scala | 6 - .../ambiguous-named-tuple-assignment.check | 19 + .../ambiguous-named-tuple-assignment.scala | 19 + tests/rewrites/unused.check | 55 + tests/rewrites/unused.scala | 61 + tests/semanticdb/metac.expect | 265 +-- tests/untried/neg/warn-unused-privates.scala | 105 -- tests/{pos => warn}/i15226.scala | 0 tests/warn/i15503a.scala | 89 +- tests/warn/i15503b.scala | 4 +- tests/warn/i15503c.scala | 22 +- tests/warn/i15503d.scala | 128 +- tests/warn/i15503e.scala | 39 +- tests/warn/i15503f.scala | 44 +- tests/warn/i15503g.scala | 7 +- tests/warn/i15503h.scala | 8 +- tests/warn/i15503i.scala | 105 +- tests/warn/i15503k.scala | 43 + tests/warn/i15503kb/power.scala | 14 + tests/warn/i15503kb/square.scala | 5 + tests/{pos => warn}/i15967.scala | 0 tests/warn/i16639a.scala | 46 +- tests/{pos => warn}/i17230.min1.scala | 0 tests/{pos => warn}/i17230.orig.scala | 0 tests/{pos => warn}/i17314.scala | 6 +- tests/{pos => warn}/i17314a.scala | 2 +- tests/warn/i17314b.scala | 2 +- tests/warn/i17318.scala | 33 + tests/warn/i17371.scala | 39 + tests/warn/i17667.scala | 10 + tests/warn/i17667b.scala | 22 + tests/warn/i17753.scala | 10 + tests/warn/i18313.scala | 14 + tests/warn/i18366.scala | 19 + tests/warn/i18564.scala | 39 + tests/warn/i19252.scala | 13 + tests/warn/i19657-mega.scala | 4 + tests/warn/i19657.scala | 117 ++ tests/warn/i20520.scala | 11 + tests/{pos => warn}/i20860.scala | 2 + tests/warn/i20951.scala | 7 + tests/warn/i21420.scala | 6 +- tests/warn/i21525.scala | 20 + tests/warn/i21809.scala | 17 + tests/warn/i21917.scala | 27 + tests/warn/i22371.scala | 8 + tests/warn/i3323.scala | 8 + tests/{pos => warn}/patmat-exhaustive.scala | 6 +- tests/warn/scala2-t11681.scala | 24 +- tests/warn/tuple-exhaustivity.scala | 6 + tests/warn/unused-can-equal.scala | 16 + tests/warn/unused-locals.scala | 43 + tests/warn/unused-params.scala | 159 ++ tests/warn/unused-privates.scala | 310 +++ 81 files changed, 2764 insertions(+), 1340 deletions(-) create mode 100644 compiler/src/dotty/tools/dotc/util/chaining.scala delete mode 100644 tests/pos/i18366.scala delete mode 100644 tests/pos/i3323.scala delete mode 100644 tests/pos/tuple-exaustivity.scala create mode 100644 tests/rewrites/ambiguous-named-tuple-assignment.check create mode 100644 tests/rewrites/ambiguous-named-tuple-assignment.scala create mode 100644 tests/rewrites/unused.check create mode 100644 tests/rewrites/unused.scala delete mode 100644 tests/untried/neg/warn-unused-privates.scala rename tests/{pos => warn}/i15226.scala (100%) create mode 100644 tests/warn/i15503k.scala create mode 100644 tests/warn/i15503kb/power.scala create mode 100644 tests/warn/i15503kb/square.scala rename tests/{pos => warn}/i15967.scala (100%) rename tests/{pos => warn}/i17230.min1.scala (100%) rename tests/{pos => warn}/i17230.orig.scala (100%) rename tests/{pos => warn}/i17314.scala (84%) rename tests/{pos => warn}/i17314a.scala (70%) create mode 100644 tests/warn/i17318.scala create mode 100644 tests/warn/i17371.scala create mode 100644 tests/warn/i17667.scala create mode 100644 tests/warn/i17667b.scala create mode 100644 tests/warn/i17753.scala create mode 100644 tests/warn/i18313.scala create mode 100644 tests/warn/i18366.scala create mode 100644 tests/warn/i18564.scala create mode 100644 tests/warn/i19252.scala create mode 100644 tests/warn/i19657-mega.scala create mode 100644 tests/warn/i19657.scala create mode 100644 tests/warn/i20520.scala rename tests/{pos => warn}/i20860.scala (74%) create mode 100644 tests/warn/i20951.scala create mode 100644 tests/warn/i21525.scala create mode 100644 tests/warn/i21809.scala create mode 100644 tests/warn/i21917.scala create mode 100644 tests/warn/i22371.scala create mode 100644 tests/warn/i3323.scala rename tests/{pos => warn}/patmat-exhaustive.scala (56%) create mode 100644 tests/warn/tuple-exhaustivity.scala create mode 100644 tests/warn/unused-can-equal.scala create mode 100644 tests/warn/unused-locals.scala create mode 100644 tests/warn/unused-params.scala create mode 100644 tests/warn/unused-privates.scala diff --git a/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala b/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala index ef65b699d06d..955597261327 100644 --- a/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala +++ b/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala @@ -818,7 +818,7 @@ trait BCodeSkelBuilder extends BCodeHelpers { methSymbol = dd.symbol jMethodName = methSymbol.javaSimpleName - returnType = asmMethodType(dd.symbol).returnType + returnType = asmMethodType(methSymbol).returnType isMethSymStaticCtor = methSymbol.isStaticConstructor resetMethodBookkeeping(dd) @@ -915,7 +915,7 @@ trait BCodeSkelBuilder extends BCodeHelpers { for (p <- params) { emitLocalVarScope(p.symbol, veryFirstProgramPoint, onePastLastProgramPoint, force = true) } } - if (isMethSymStaticCtor) { appendToStaticCtor(dd) } + if (isMethSymStaticCtor) { appendToStaticCtor() } } // end of emitNormalMethodBody() lineNumber(rhs) @@ -936,7 +936,7 @@ trait BCodeSkelBuilder extends BCodeHelpers { * * TODO document, explain interplay with `fabricateStaticInitAndroid()` */ - private def appendToStaticCtor(dd: DefDef): Unit = { + private def appendToStaticCtor(): Unit = { def insertBefore( location: asm.tree.AbstractInsnNode, diff --git a/compiler/src/dotty/tools/dotc/Compiler.scala b/compiler/src/dotty/tools/dotc/Compiler.scala index b3757a9ddce7..c888dabdd61f 100644 --- a/compiler/src/dotty/tools/dotc/Compiler.scala +++ b/compiler/src/dotty/tools/dotc/Compiler.scala @@ -8,7 +8,6 @@ import cc.CheckCaptures import parsing.Parser import Phases.Phase import transform.* -import dotty.tools.backend import backend.jvm.{CollectSuperCalls, GenBCode} import localopt.StringInterpolatorOpt @@ -35,8 +34,7 @@ class Compiler { protected def frontendPhases: List[List[Phase]] = List(new Parser) :: // Compiler frontend: scanner, parser List(new TyperPhase) :: // Compiler frontend: namer, typer - List(new CheckUnused.PostTyper) :: // Check for unused elements - List(new CheckShadowing) :: // Check shadowing elements + List(CheckUnused.PostTyper(), CheckShadowing()) :: // Check for unused, shadowed elements List(new YCheckPositions) :: // YCheck positions List(new sbt.ExtractDependencies) :: // Sends information on classes' dependencies to sbt via callbacks List(new semanticdb.ExtractSemanticDB.ExtractSemanticInfo) :: // Extract info into .semanticdb files @@ -51,10 +49,10 @@ class Compiler { List(new Pickler) :: // Generate TASTY info List(new Inlining) :: // Inline and execute macros List(new PostInlining) :: // Add mirror support for inlined code - List(new CheckUnused.PostInlining) :: // Check for unused elements List(new Staging) :: // Check staging levels and heal staged types List(new Splicing) :: // Replace level 1 splices with holes List(new PickleQuotes) :: // Turn quoted trees into explicit run-time data structures + List(new CheckUnused.PostInlining) :: // Check for unused elements Nil /** Phases dealing with the transformation from pickled trees to backend trees */ diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 9db12e21913a..ca180e5ea612 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -45,6 +45,14 @@ object desugar { */ val UntupledParam: Property.Key[Unit] = Property.StickyKey() + /** An attachment key to indicate that a ValDef originated from a pattern. + */ + val PatternVar: Property.Key[Unit] = Property.StickyKey() + + /** An attachment key for Trees originating in for-comprehension, such as tupling of assignments. + */ + val ForArtifact: Property.Key[Unit] = Property.StickyKey() + /** What static check should be applied to a Match? */ enum MatchCheck { case None, Exhaustive, IrrefutablePatDef, IrrefutableGenFrom @@ -1221,7 +1229,7 @@ object desugar { val matchExpr = if (tupleOptimizable) rhs else - val caseDef = CaseDef(pat, EmptyTree, makeTuple(ids)) + val caseDef = CaseDef(pat, EmptyTree, makeTuple(ids).withAttachment(ForArtifact, ())) Match(makeSelector(rhs, MatchCheck.IrrefutablePatDef), caseDef :: Nil) vars match { case Nil if !mods.is(Lazy) => @@ -1251,6 +1259,7 @@ object desugar { ValDef(named.name.asTermName, tpt, selector(n)) .withMods(mods) .withSpan(named.span) + .withAttachment(PatternVar, ()) ) flatTree(firstDef :: restDefs) } @@ -1542,6 +1551,7 @@ object desugar { val vdef = ValDef(named.name.asTermName, tpt, rhs) .withMods(mods) .withSpan(original.span.withPoint(named.span.start)) + .withAttachment(PatternVar, ()) val mayNeedSetter = valDef(vdef) mayNeedSetter } @@ -1733,7 +1743,7 @@ object desugar { case _ => Modifiers() makePatDef(valeq, mods, defpat, rhs) } - val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom(defpat0, gen.expr, gen.checkMode) :: Nil, Block(pdefs, makeTuple(id0 :: ids))) + val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom(defpat0, gen.expr, gen.checkMode) :: Nil, Block(pdefs, makeTuple(id0 :: ids).withAttachment(ForArtifact, ()))) val allpats = gen.pat :: pats val vfrom1 = GenFrom(makeTuple(allpats), rhs1, GenCheckMode.Ignore) makeFor(mapName, flatMapName, vfrom1 :: rest1, body) diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 6928e0617069..b864446f19d5 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -179,28 +179,20 @@ private sealed trait WarningSettings: choices = List( ChoiceWithHelp("nowarn", ""), ChoiceWithHelp("all", ""), - ChoiceWithHelp( - name = "imports", - description = "Warn if an import selector is not referenced.\n" + - "NOTE : overrided by -Wunused:strict-no-implicit-warn"), + ChoiceWithHelp("imports", "Warn if an import selector is not referenced."), ChoiceWithHelp("privates", "Warn if a private member is unused"), ChoiceWithHelp("locals", "Warn if a local definition is unused"), ChoiceWithHelp("explicits", "Warn if an explicit parameter is unused"), ChoiceWithHelp("implicits", "Warn if an implicit parameter is unused"), ChoiceWithHelp("params", "Enable -Wunused:explicits,implicits"), + ChoiceWithHelp("patvars","Warn if a variable bound in a pattern is unused"), + //ChoiceWithHelp("inlined", "Apply -Wunused to inlined expansions"), // TODO ChoiceWithHelp("linted", "Enable -Wunused:imports,privates,locals,implicits"), ChoiceWithHelp( name = "strict-no-implicit-warn", description = "Same as -Wunused:import, only for imports of explicit named members.\n" + "NOTE : This overrides -Wunused:imports and NOT set by -Wunused:all" ), - // ChoiceWithHelp("patvars","Warn if a variable bound in a pattern is unused"), - ChoiceWithHelp( - name = "unsafe-warn-patvars", - description = "(UNSAFE) Warn if a variable bound in a pattern is unused.\n" + - "This warning can generate false positive, as warning cannot be\n" + - "suppressed yet." - ) ), default = Nil ) @@ -212,7 +204,6 @@ private sealed trait WarningSettings: // Is any choice set for -Wunused? def any(using Context): Boolean = Wall.value || Wunused.value.nonEmpty - // overrided by strict-no-implicit-warn def imports(using Context) = (allOr("imports") || allOr("linted")) && !(strictNoImplicitWarn) def locals(using Context) = @@ -226,9 +217,8 @@ private sealed trait WarningSettings: def params(using Context) = allOr("params") def privates(using Context) = allOr("privates") || allOr("linted") - def patvars(using Context) = - isChoiceSet("unsafe-warn-patvars") // not with "all" - // allOr("patvars") // todo : rename once fixed + def patvars(using Context) = allOr("patvars") + def inlined(using Context) = isChoiceSet("inlined") def linted(using Context) = allOr("linted") def strictNoImplicitWarn(using Context) = diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 4aed3d310b03..26ddc47c6b89 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -482,6 +482,8 @@ class Definitions { @tu lazy val Predef_undefined: Symbol = ScalaPredefModule.requiredMethod(nme.???) @tu lazy val ScalaPredefModuleClass: ClassSymbol = ScalaPredefModule.moduleClass.asClass + @tu lazy val SameTypeClass: ClassSymbol = requiredClass("scala.=:=") + @tu lazy val SameType_refl: Symbol = SameTypeClass.companionModule.requiredMethod(nme.refl) @tu lazy val SubTypeClass: ClassSymbol = requiredClass("scala.<:<") @tu lazy val SubType_refl: Symbol = SubTypeClass.companionModule.requiredMethod(nme.refl) @@ -816,6 +818,7 @@ class Definitions { @tu lazy val QuotedExprClass: ClassSymbol = requiredClass("scala.quoted.Expr") @tu lazy val QuotesClass: ClassSymbol = requiredClass("scala.quoted.Quotes") + @tu lazy val Quotes_reflectModule: Symbol = QuotesClass.requiredClass("reflectModule") @tu lazy val Quotes_reflect: Symbol = QuotesClass.requiredValue("reflect") @tu lazy val Quotes_reflect_asTerm: Symbol = Quotes_reflect.requiredMethod("asTerm") @tu lazy val Quotes_reflect_Apply: Symbol = Quotes_reflect.requiredValue("Apply") @@ -941,6 +944,7 @@ class Definitions { def NonEmptyTupleClass(using Context): ClassSymbol = NonEmptyTupleTypeRef.symbol.asClass lazy val NonEmptyTuple_tail: Symbol = NonEmptyTupleClass.requiredMethod("tail") @tu lazy val PairClass: ClassSymbol = requiredClass("scala.*:") + @tu lazy val PairClass_unapply: Symbol = PairClass.companionModule.requiredMethod("unapply") @tu lazy val TupleXXLClass: ClassSymbol = requiredClass("scala.runtime.TupleXXL") def TupleXXLModule(using Context): Symbol = TupleXXLClass.companionModule @@ -1031,6 +1035,7 @@ class Definitions { @tu lazy val UncheckedCapturesAnnot: ClassSymbol = requiredClass("scala.annotation.unchecked.uncheckedCaptures") @tu lazy val VolatileAnnot: ClassSymbol = requiredClass("scala.volatile") @tu lazy val WithPureFunsAnnot: ClassSymbol = requiredClass("scala.annotation.internal.WithPureFuns") + @tu lazy val LanguageFeatureMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.languageFeature") @tu lazy val BeanGetterMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.beanGetter") @tu lazy val BeanSetterMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.beanSetter") @tu lazy val FieldMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.field") diff --git a/compiler/src/dotty/tools/dotc/report.scala b/compiler/src/dotty/tools/dotc/report.scala index 5517bd005077..7bc301184022 100644 --- a/compiler/src/dotty/tools/dotc/report.scala +++ b/compiler/src/dotty/tools/dotc/report.scala @@ -1,13 +1,11 @@ package dotty.tools.dotc -import reporting.* -import Diagnostic.* -import util.{SourcePosition, NoSourcePosition, SrcPos} -import core.* -import Contexts.*, Flags.*, Symbols.*, Decorators.* -import config.SourceVersion import ast.* -import config.Feature.sourceVersion +import core.*, Contexts.*, Flags.*, Symbols.*, Decorators.* +import config.Feature.sourceVersion, config.SourceVersion +import reporting.*, Diagnostic.* +import util.{SourcePosition, NoSourcePosition, SrcPos} + import java.lang.System.currentTimeMillis object report: @@ -54,6 +52,9 @@ object report: else issueWarning(new FeatureWarning(msg, pos.sourcePos)) end featureWarning + def warning(msg: Message, pos: SrcPos, origin: String)(using Context): Unit = + issueWarning(LintWarning(msg, addInlineds(pos), origin)) + def warning(msg: Message, pos: SrcPos)(using Context): Unit = issueWarning(new Warning(msg, addInlineds(pos))) diff --git a/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala b/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala index 6a2d88f4e82f..102572b82bbc 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala @@ -36,6 +36,18 @@ object Diagnostic: pos: SourcePosition ) extends Error(msg, pos) + /** A Warning with an origin. The semantics of `origin` depend on the warning. + * For example, an unused import warning has an origin that specifies the unused selector. + * The origin of a deprecation is the deprecated element. + */ + trait OriginWarning(val origin: String): + self: Warning => + + /** Lints are likely to be filtered. Provide extra axes for filtering by `-Wconf`. + */ + class LintWarning(msg: Message, pos: SourcePosition, origin: String) + extends Warning(msg, pos), OriginWarning(origin) + class Warning( msg: Message, pos: SourcePosition @@ -73,13 +85,9 @@ object Diagnostic: def enablingOption(using Context): Setting[Boolean] = ctx.settings.unchecked } - class DeprecationWarning( - msg: Message, - pos: SourcePosition, - val origin: String - ) extends ConditionalWarning(msg, pos) { + class DeprecationWarning(msg: Message, pos: SourcePosition, origin: String) + extends ConditionalWarning(msg, pos), OriginWarning(origin): def enablingOption(using Context): Setting[Boolean] = ctx.settings.deprecation - } class MigrationWarning( msg: Message, @@ -104,5 +112,5 @@ class Diagnostic( override def diagnosticRelatedInformation: JList[interfaces.DiagnosticRelatedInformation] = Collections.emptyList() - override def toString: String = s"$getClass at $pos: $message" + override def toString: String = s"$getClass at $pos L${pos.line+1}: $message" end Diagnostic diff --git a/compiler/src/dotty/tools/dotc/reporting/WConf.scala b/compiler/src/dotty/tools/dotc/reporting/WConf.scala index b1afc2ab5dba..fd5c7cc0dbeb 100644 --- a/compiler/src/dotty/tools/dotc/reporting/WConf.scala +++ b/compiler/src/dotty/tools/dotc/reporting/WConf.scala @@ -14,11 +14,13 @@ import scala.annotation.internal.sharable import scala.util.matching.Regex enum MessageFilter: - def matches(message: Diagnostic): Boolean = this match + def matches(message: Diagnostic): Boolean = + import Diagnostic.* + this match case Any => true - case Deprecated => message.isInstanceOf[Diagnostic.DeprecationWarning] - case Feature => message.isInstanceOf[Diagnostic.FeatureWarning] - case Unchecked => message.isInstanceOf[Diagnostic.UncheckedWarning] + case Deprecated => message.isInstanceOf[DeprecationWarning] + case Feature => message.isInstanceOf[FeatureWarning] + case Unchecked => message.isInstanceOf[UncheckedWarning] case MessageID(errorId) => message.msg.errorId == errorId case MessagePattern(pattern) => val noHighlight = message.msg.message.replaceAll("\\e\\[[\\d;]*[^\\d;]","") @@ -31,7 +33,7 @@ enum MessageFilter: pattern.findFirstIn(path).nonEmpty case Origin(pattern) => message match - case message: Diagnostic.DeprecationWarning => pattern.findFirstIn(message.origin).nonEmpty + case message: OriginWarning => pattern.findFirstIn(message.origin).nonEmpty case _ => false case None => false @@ -56,12 +58,12 @@ object WConf: private type Conf = (List[MessageFilter], Action) def parseAction(s: String): Either[List[String], Action] = s match - case "error" | "e" => Right(Error) - case "warning" | "w" => Right(Warning) - case "verbose" | "v" => Right(Verbose) - case "info" | "i" => Right(Info) - case "silent" | "s" => Right(Silent) - case _ => Left(List(s"unknown action: `$s`")) + case "error" | "e" => Right(Error) + case "warning" | "w" => Right(Warning) + case "verbose" | "v" => Right(Verbose) + case "info" | "i" => Right(Info) + case "silent" | "s" => Right(Silent) + case _ => Left(List(s"unknown action: `$s`")) private def regex(s: String) = try Right(s.r) diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index f9210845bd54..886ed3979ba5 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -3155,22 +3155,25 @@ extends SyntaxMsg(VolatileOnValID): protected def msg(using Context): String = "values cannot be volatile" protected def explain(using Context): String = "" -class UnusedSymbol(errorText: String)(using Context) + +class UnusedSymbol(errorText: String, val actions: List[CodeAction] = Nil)(using Context) extends Message(UnusedSymbolID) { def kind = MessageKind.UnusedSymbol override def msg(using Context) = errorText override def explain(using Context) = "" -} - -object UnusedSymbol { - def imports(using Context): UnusedSymbol = new UnusedSymbol(i"unused import") - def localDefs(using Context): UnusedSymbol = new UnusedSymbol(i"unused local definition") - def explicitParams(using Context): UnusedSymbol = new UnusedSymbol(i"unused explicit parameter") - def implicitParams(using Context): UnusedSymbol = new UnusedSymbol(i"unused implicit parameter") - def privateMembers(using Context): UnusedSymbol = new UnusedSymbol(i"unused private member") - def patVars(using Context): UnusedSymbol = new UnusedSymbol(i"unused pattern variable") -} + override def actions(using Context) = this.actions +} + +object UnusedSymbol: + def imports(actions: List[CodeAction])(using Context): UnusedSymbol = UnusedSymbol(i"unused import", actions) + def localDefs(using Context): UnusedSymbol = UnusedSymbol(i"unused local definition") + def explicitParams(using Context): UnusedSymbol = UnusedSymbol(i"unused explicit parameter") + def implicitParams(using Context): UnusedSymbol = UnusedSymbol(i"unused implicit parameter") + def privateMembers(using Context): UnusedSymbol = UnusedSymbol(i"unused private member") + def patVars(using Context): UnusedSymbol = UnusedSymbol(i"unused pattern variable") + def unsetLocals(using Context): UnusedSymbol = UnusedSymbol(i"unset local variable, consider using an immutable val instead") + def unsetPrivates(using Context): UnusedSymbol = UnusedSymbol(i"unset private variable, consider using an immutable val instead") final class QuotedTypeMissing(tpe: Type)(using Context) extends StagingMessage(QuotedTypeMissingID): diff --git a/compiler/src/dotty/tools/dotc/transform/CheckShadowing.scala b/compiler/src/dotty/tools/dotc/transform/CheckShadowing.scala index a85cabdd5460..7ecdf79af984 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckShadowing.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckShadowing.scala @@ -49,26 +49,22 @@ class CheckShadowing extends MiniPhase: override def description: String = CheckShadowing.description + override def isEnabled(using Context): Boolean = ctx.settings.Xlint.value.nonEmpty + override def isRunnable(using Context): Boolean = - super.isRunnable && - ctx.settings.Xlint.value.nonEmpty && - !ctx.isJava + super.isRunnable && ctx.settings.Xlint.value.nonEmpty && !ctx.isJava - // Setup before the traversal override def prepareForUnit(tree: tpd.Tree)(using Context): Context = val data = ShadowingData() val fresh = ctx.fresh.setProperty(_key, data) shadowingDataApply(sd => sd.registerRootImports())(using fresh) - // Reporting on traversal's end override def transformUnit(tree: tpd.Tree)(using Context): tpd.Tree = shadowingDataApply(sd => reportShadowing(sd.getShadowingResult) ) tree - // MiniPhase traversal : - override def prepareForPackageDef(tree: tpd.PackageDef)(using Context): Context = shadowingDataApply(sd => sd.inNewScope()) ctx @@ -91,16 +87,16 @@ class CheckShadowing extends MiniPhase: ) override def prepareForTypeDef(tree: tpd.TypeDef)(using Context): Context = - if tree.symbol.isAliasType then // if alias, the parent is the current symbol - nestedTypeTraverser(tree.symbol).traverse(tree.rhs) - if tree.symbol.is(Param) then // if param, the parent is up - val owner = tree.symbol.owner + val sym = tree.symbol + if sym.isAliasType then // if alias, the parent is the current symbol + nestedTypeTraverser(sym).traverse(tree.rhs) + if sym.is(Param) then // if param, the parent is up + val owner = sym.owner val parent = if (owner.isConstructor) then owner.owner else owner nestedTypeTraverser(parent).traverse(tree.rhs)(using ctx.outer) - shadowingDataApply(sd => sd.registerCandidate(parent, tree)) - else - ctx - + if isValidTypeParamOwner(sym.owner) then + shadowingDataApply(sd => sd.registerCandidate(parent, tree)) + ctx override def transformPackageDef(tree: tpd.PackageDef)(using Context): tpd.Tree = shadowingDataApply(sd => sd.outOfScope()) @@ -115,13 +111,14 @@ class CheckShadowing extends MiniPhase: tree override def transformTypeDef(tree: tpd.TypeDef)(using Context): tpd.Tree = - if tree.symbol.is(Param) && isValidTypeParamOwner(tree.symbol.owner) then // Do not register for constructors the work is done for the Class owned equivalent TypeDef + // Do not register for constructors the work is done for the Class owned equivalent TypeDef + if tree.symbol.is(Param) && isValidTypeParamOwner(tree.symbol.owner) then shadowingDataApply(sd => sd.computeTypeParamShadowsFor(tree.symbol.owner)(using ctx.outer)) - if tree.symbol.isAliasType then // No need to start outer here, because the TypeDef reached here it's already the parent + // No need to start outer here, because the TypeDef reached here it's already the parent + if tree.symbol.isAliasType then shadowingDataApply(sd => sd.computeTypeParamShadowsFor(tree.symbol)(using ctx)) tree - // Helpers : private def isValidTypeParamOwner(owner: Symbol)(using Context): Boolean = !owner.isConstructor && !owner.is(Synthetic) && !owner.is(Exported) @@ -141,7 +138,7 @@ class CheckShadowing extends MiniPhase: override def traverse(tree: tpd.Tree)(using Context): Unit = tree match - case t:tpd.TypeDef => + case t: tpd.TypeDef => val newCtx = shadowingDataApply(sd => sd.registerCandidate(parent, t) ) @@ -157,7 +154,7 @@ class CheckShadowing extends MiniPhase: override def traverse(tree: tpd.Tree)(using Context): Unit = tree match - case t:tpd.Import => + case t: tpd.Import => val newCtx = shadowingDataApply(sd => sd.registerImport(t)) traverseChildren(tree)(using newCtx) case _ => @@ -240,7 +237,7 @@ object CheckShadowing: val declarationScope = ctx.effectiveScope val res = declarationScope.lookup(symbol.name) res match - case s: Symbol if s.isType => Some(s) + case s: Symbol if s.isType && s != symbol => Some(s) case _ => lookForUnitShadowedType(symbol)(using ctx.outer) /** Register if the valDef is a private declaration that shadows an inherited field */ @@ -310,4 +307,3 @@ object CheckShadowing: case class ShadowResult(warnings: List[ShadowWarning]) end CheckShadowing - diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index 6e626fc5dd9e..dc15bb80cbb6 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -1,883 +1,905 @@ package dotty.tools.dotc.transform -import scala.annotation.tailrec -import scala.collection.mutable - -import dotty.tools.uncheckedNN -import dotty.tools.dotc.ast.tpd -import dotty.tools.dotc.core.Symbols.* -import dotty.tools.dotc.ast.tpd.{Inlined, TreeTraverser} -import dotty.tools.dotc.ast.untpd -import dotty.tools.dotc.ast.untpd.ImportSelector +import dotty.tools.dotc.ast.desugar.{ForArtifact, PatternVar} +import dotty.tools.dotc.ast.tpd.* +import dotty.tools.dotc.ast.untpd, untpd.ImportSelector import dotty.tools.dotc.config.ScalaSettings import dotty.tools.dotc.core.Contexts.* -import dotty.tools.dotc.core.Decorators.{em, i} -import dotty.tools.dotc.core.Denotations.SingleDenotation import dotty.tools.dotc.core.Flags.* -import dotty.tools.dotc.core.Phases.Phase -import dotty.tools.dotc.core.StdNames +import dotty.tools.dotc.core.Names.{Name, SimpleName, DerivedName, TermName, termName} +import dotty.tools.dotc.core.NameOps.{isAnonymousFunctionName, isReplWrapperName} +import dotty.tools.dotc.core.NameKinds.{ContextBoundParamName, ContextFunctionParamName, WildcardParamName} +import dotty.tools.dotc.core.StdNames.nme +import dotty.tools.dotc.core.Symbols.{ClassSymbol, NoSymbol, Symbol, defn, isDeprecated, requiredClass, requiredModule} +import dotty.tools.dotc.core.Types.* import dotty.tools.dotc.report -import dotty.tools.dotc.reporting.Message -import dotty.tools.dotc.reporting.UnusedSymbol as UnusedSymbolMessage -import dotty.tools.dotc.typer.ImportInfo -import dotty.tools.dotc.util.{Property, SrcPos} -import dotty.tools.dotc.core.Mode -import dotty.tools.dotc.core.Types.{AnnotatedType, ConstantType, NoType, TermRef, Type, TypeTraverser} -import dotty.tools.dotc.core.Flags.flagsString -import dotty.tools.dotc.core.Flags -import dotty.tools.dotc.core.Names.{Name, TermName} -import dotty.tools.dotc.core.NameOps.isReplWrapperName +import dotty.tools.dotc.reporting.{CodeAction, UnusedSymbol} +import dotty.tools.dotc.rewrites.Rewrites import dotty.tools.dotc.transform.MegaPhase.MiniPhase -import dotty.tools.dotc.core.Annotations -import dotty.tools.dotc.core.Definitions -import dotty.tools.dotc.core.NameKinds.WildcardParamName -import dotty.tools.dotc.core.Symbols.Symbol -import dotty.tools.dotc.core.StdNames.nme -import dotty.tools.dotc.util.Spans.Span -import scala.math.Ordering +import dotty.tools.dotc.typer.{ImportInfo, Typer} +import dotty.tools.dotc.typer.Deriving.OriginalTypeClass +import dotty.tools.dotc.util.{Property, Spans, SrcPos}, Spans.Span +import dotty.tools.dotc.util.Chars.{isLineBreakChar, isWhitespace} +import dotty.tools.dotc.util.chaining.* +import java.util.IdentityHashMap -/** - * A compiler phase that checks for unused imports or definitions - * - * Basically, it gathers definition/imports and their usage. If a - * definition/imports does not have any usage, then it is reported. - */ -class CheckUnused private (phaseMode: CheckUnused.PhaseMode, suffix: String, _key: Property.Key[CheckUnused.UnusedData]) extends MiniPhase: - import CheckUnused.* - import UnusedData.* - - private inline def unusedDataApply[U](inline f: UnusedData => U)(using Context): Context = - ctx.property(_key) match - case Some(ud) => f(ud) - case None => () - ctx +import scala.collection.mutable, mutable.{ArrayBuilder, ListBuffer, Stack} - override def phaseName: String = CheckUnused.phaseNamePrefix + suffix +import CheckUnused.* - override def description: String = CheckUnused.description +/** A compiler phase that checks for unused imports or definitions. + */ +class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPhase: - override def isRunnable(using Context): Boolean = - super.isRunnable && - ctx.settings.WunusedHas.any && - !ctx.isJava + override def phaseName: String = s"checkUnused$suffix" - // ========== SETUP ============ + override def description: String = "check for unused elements" - override def prepareForUnit(tree: tpd.Tree)(using Context): Context = - val data = UnusedData() - tree.getAttachment(_key).foreach(oldData => - data.unusedAggregate = oldData.unusedAggregate - ) - val fresh = ctx.fresh.setProperty(_key, data) - tree.putAttachment(_key, data) - fresh + override def isEnabled(using Context): Boolean = ctx.settings.WunusedHas.any - // ========== END + REPORTING ========== + override def isRunnable(using Context): Boolean = super.isRunnable && ctx.settings.WunusedHas.any && !ctx.isJava - override def transformUnit(tree: tpd.Tree)(using Context): tpd.Tree = - unusedDataApply { ud => - ud.finishAggregation() - if(phaseMode == PhaseMode.Report) then - ud.unusedAggregate.foreach(reportUnused) - } + override def prepareForUnit(tree: Tree)(using Context): Context = + val infos = tree.getAttachment(refInfosKey).getOrElse: + RefInfos().tap(tree.withAttachment(refInfosKey, _)) + ctx.fresh.setProperty(refInfosKey, infos) + override def transformUnit(tree: Tree)(using Context): tree.type = + if phaseMode == PhaseMode.Report then + reportUnused() + tree.removeAttachment(refInfosKey) tree - // ========== MiniPhase Prepare ========== - override def prepareForOther(tree: tpd.Tree)(using Context): Context = - // A standard tree traverser covers cases not handled by the Mega/MiniPhase - traverser.traverse(tree) - ctx - - override def prepareForInlined(tree: tpd.Inlined)(using Context): Context = - traverser.traverse(tree.call) - ctx - - override def prepareForIdent(tree: tpd.Ident)(using Context): Context = + override def transformIdent(tree: Ident)(using Context): tree.type = if tree.symbol.exists then - unusedDataApply { ud => - @tailrec - def loopOnNormalizedPrefixes(prefix: Type, depth: Int): Unit = - // limit to 10 as failsafe for the odd case where there is an infinite cycle - if depth < 10 && prefix.exists then - ud.registerUsed(prefix.classSymbol, None) - loopOnNormalizedPrefixes(prefix.normalizedPrefix, depth + 1) - - loopOnNormalizedPrefixes(tree.typeOpt.normalizedPrefix, depth = 0) - ud.registerUsed(tree.symbol, Some(tree.name)) - } + // if in an inline expansion, resolve at summonInline (synthetic pos) or in an enclosing call site + val resolving = + refInfos.inlined.isEmpty + || tree.srcPos.isZeroExtentSynthetic + || refInfos.inlined.exists(_.sourcePos.contains(tree.srcPos.sourcePos)) + if resolving && !ignoreTree(tree) then + resolveUsage(tree.symbol, tree.name, tree.typeOpt.importPrefix.skipPackageObject) else if tree.hasType then - unusedDataApply(_.registerUsed(tree.tpe.classSymbol, Some(tree.name))) + resolveUsage(tree.tpe.classSymbol, tree.name, tree.tpe.importPrefix.skipPackageObject) + tree + + // import x.y; y may be rewritten x.y, also import x.z as y + override def transformSelect(tree: Select)(using Context): tree.type = + val name = tree.removeAttachment(OriginalName).getOrElse(nme.NO_NAME) + if tree.span.isSynthetic && tree.symbol == defn.TypeTest_unapply then + tree.qualifier.tpe.underlying.finalResultType match + case AppliedType(_, args) => // tycon.typeSymbol == defn.TypeTestClass + val res = args(1) // T in TypeTest[-S, T] + val target = res.dealias.typeSymbol + resolveUsage(target, target.name, res.importPrefix.skipPackageObject) // case _: T => + case _ => + else if tree.qualifier.span.isSynthetic || name.exists(_ != tree.symbol.name) then + if !ignoreTree(tree) then + resolveUsage(tree.symbol, name, tree.qualifier.tpe) else - ctx - - override def prepareForSelect(tree: tpd.Select)(using Context): Context = - val name = tree.removeAttachment(OriginalName) - unusedDataApply(_.registerUsed(tree.symbol, name, includeForImport = tree.qualifier.span.isSynthetic)) - - override def prepareForBlock(tree: tpd.Block)(using Context): Context = - pushInBlockTemplatePackageDef(tree) - - override def prepareForTemplate(tree: tpd.Template)(using Context): Context = - pushInBlockTemplatePackageDef(tree) - - override def prepareForPackageDef(tree: tpd.PackageDef)(using Context): Context = - pushInBlockTemplatePackageDef(tree) - - override def prepareForValDef(tree: tpd.ValDef)(using Context): Context = - unusedDataApply{ud => - // do not register the ValDef generated for `object` - traverseAnnotations(tree.symbol) - if !tree.symbol.is(Module) then - ud.registerDef(tree) - if tree.name.startsWith("derived$") && tree.typeOpt != NoType then - ud.registerUsed(tree.typeOpt.typeSymbol, None, isDerived = true) - ud.addIgnoredUsage(tree.symbol) - } - - override def prepareForDefDef(tree: tpd.DefDef)(using Context): Context = - unusedDataApply: ud => - if !tree.symbol.is(Private) then - tree.termParamss.flatten.foreach { p => - ud.addIgnoredParam(p.symbol) - } - ud.registerTrivial(tree) - traverseAnnotations(tree.symbol) - ud.registerDef(tree) - ud.addIgnoredUsage(tree.symbol) - - override def prepareForTypeDef(tree: tpd.TypeDef)(using Context): Context = - unusedDataApply: ud => - traverseAnnotations(tree.symbol) - if !tree.symbol.is(Param) then // Ignore type parameter (as Scala 2) - ud.registerDef(tree) - ud.addIgnoredUsage(tree.symbol) - - override def prepareForBind(tree: tpd.Bind)(using Context): Context = - traverseAnnotations(tree.symbol) - unusedDataApply(_.registerPatVar(tree)) + refUsage(tree.symbol) + tree - override def prepareForTypeTree(tree: tpd.TypeTree)(using Context): Context = - if !tree.isInstanceOf[tpd.InferredTypeTree] then typeTraverser(unusedDataApply).traverse(tree.tpe) - ctx + override def transformLiteral(tree: Literal)(using Context): tree.type = + tree.getAttachment(Typer.AdaptedTree).foreach(transformAllDeep) + tree - override def prepareForAssign(tree: tpd.Assign)(using Context): Context = - unusedDataApply{ ud => - val sym = tree.lhs.symbol - if sym.exists then - ud.registerSetVar(sym) - } + override def prepareForCaseDef(tree: CaseDef)(using Context): Context = + nowarner.traverse(tree.pat) + ctx - // ========== MiniPhase Transform ========== + override def prepareForApply(tree: Apply)(using Context): Context = + // ignore tupling of for assignments, as they are not usages of vars + if tree.hasAttachment(ForArtifact) then + tree match + case Apply(TypeApply(Select(fun, nme.apply), _), args) => + if fun.symbol.is(Module) && defn.isTupleClass(fun.symbol.companionClass) then + args.foreach(_.withAttachment(ForArtifact, ())) + case _ => + ctx - override def transformBlock(tree: tpd.Block)(using Context): tpd.Tree = - popOutBlockTemplatePackageDef() + override def prepareForAssign(tree: Assign)(using Context): Context = + tree.lhs.putAttachment(Ignore, ()) // don't take LHS reference as a read + ctx + override def transformAssign(tree: Assign)(using Context): tree.type = + tree.lhs.removeAttachment(Ignore) + val sym = tree.lhs.symbol + if sym.exists then + refInfos.asss.addOne(sym) tree - override def transformTemplate(tree: tpd.Template)(using Context): tpd.Tree = - popOutBlockTemplatePackageDef() + override def prepareForMatch(tree: Match)(using Context): Context = + // exonerate case.pat against tree.selector (simple var pat only for now) + tree.selector match + case Ident(nm) => tree.cases.foreach(k => allowVariableBindings(List(nm), List(k.pat))) + case _ => + ctx + override def transformMatch(tree: Match)(using Context): tree.type = + if tree.isInstanceOf[InlineMatch] && tree.selector.isEmpty then + val sf = defn.Compiletime_summonFrom + resolveUsage(sf, sf.name, NoPrefix) tree - override def transformPackageDef(tree: tpd.PackageDef)(using Context): tpd.Tree = - popOutBlockTemplatePackageDef() + override def transformTypeTree(tree: TypeTree)(using Context): tree.type = + tree.tpe match + case AnnotatedType(_, annot) => transformAllDeep(annot.tree) + case tpt if tpt.typeSymbol.exists => resolveUsage(tpt.typeSymbol, tpt.typeSymbol.name, NoPrefix) + case _ => tree - override def transformValDef(tree: tpd.ValDef)(using Context): tpd.Tree = - unusedDataApply(_.removeIgnoredUsage(tree.symbol)) + override def prepareForInlined(tree: Inlined)(using Context): Context = + refInfos.inlined.push(tree.call.srcPos) + ctx + override def transformInlined(tree: Inlined)(using Context): tree.type = + val _ = refInfos.inlined.pop() + if !tree.call.isEmpty && phaseMode.eq(PhaseMode.Aggregate) then + transformAllDeep(tree.call) tree - override def transformDefDef(tree: tpd.DefDef)(using Context): tpd.Tree = - unusedDataApply(_.removeIgnoredUsage(tree.symbol)) + override def prepareForBind(tree: Bind)(using Context): Context = + refInfos.register(tree) + ctx + + override def prepareForValDef(tree: ValDef)(using Context): Context = + if !tree.symbol.is(Deferred) && tree.rhs.symbol != defn.Predef_undefined then + refInfos.register(tree) + ctx + override def transformValDef(tree: ValDef)(using Context): tree.type = + traverseAnnotations(tree.symbol) + if tree.name.startsWith("derived$") && tree.hasType then + def loop(t: Tree): Unit = t match + case Ident(name) => + val target = + val ts0 = t.tpe.typeSymbol + if ts0.is(ModuleClass) then ts0.companionModule else ts0 + resolveUsage(target, name, t.tpe.underlyingPrefix.skipPackageObject) + case Select(t, _) => loop(t) + case _ => + tree.getAttachment(OriginalTypeClass).foreach(loop) tree - override def transformTypeDef(tree: tpd.TypeDef)(using Context): tpd.Tree = - unusedDataApply(_.removeIgnoredUsage(tree.symbol)) + override def prepareForDefDef(tree: DefDef)(using Context): Context = + def trivial = tree.symbol.is(Deferred) || isUnconsuming(tree.rhs) + def nontrivial = tree.symbol.isConstructor || tree.symbol.isAnonymousFunction + if !nontrivial && trivial then refInfos.skip.addOne(tree.symbol) + if tree.symbol.is(Inline) then + refInfos.inliners += 1 + else if !tree.symbol.is(Deferred) && tree.rhs.symbol != defn.Predef_undefined then + refInfos.register(tree) + ctx + override def transformDefDef(tree: DefDef)(using Context): tree.type = + traverseAnnotations(tree.symbol) + if tree.symbol.is(Inline) then + refInfos.inliners -= 1 tree + override def transformTypeDef(tree: TypeDef)(using Context): tree.type = + traverseAnnotations(tree.symbol) + if !tree.symbol.is(Param) then // type parameter to do? + refInfos.register(tree) + tree - // ---------- MiniPhase HELPERS ----------- + override def prepareForTemplate(tree: Template)(using Context): Context = + ctx.fresh.setProperty(resolvedKey, Resolved()) + + override def prepareForPackageDef(tree: PackageDef)(using Context): Context = + ctx.fresh.setProperty(resolvedKey, Resolved()) + + override def prepareForStats(trees: List[Tree])(using Context): Context = + ctx.fresh.setProperty(resolvedKey, Resolved()) + + override def transformOther(tree: Tree)(using Context): tree.type = + tree match + case imp: Import => + if phaseMode eq PhaseMode.Aggregate then + refInfos.register(imp) + transformAllDeep(imp.expr) + for selector <- imp.selectors do + if selector.isGiven then + selector.bound match + case untpd.TypedSplice(bound) => transformAllDeep(bound) + case _ => + case AppliedTypeTree(tpt, args) => + transformAllDeep(tpt) + args.foreach(transformAllDeep) + case RefinedTypeTree(tpt, refinements) => + transformAllDeep(tpt) + refinements.foreach(transformAllDeep) + case LambdaTypeTree(tparams, body) => + tparams.foreach(transformAllDeep) + transformAllDeep(body) + case SingletonTypeTree(ref) => + // selftype of object is not a usage + val moduleSelfRef = ctx.owner.is(Module) && ctx.owner == tree.symbol.companionModule.moduleClass + if !moduleSelfRef then + transformAllDeep(ref) + case TypeBoundsTree(lo, hi, alias) => + transformAllDeep(lo) + transformAllDeep(hi) + transformAllDeep(alias) + case tree: NamedArg => transformAllDeep(tree.arg) + case Annotated(arg, annot) => + transformAllDeep(arg) + transformAllDeep(annot) + case Quote(body, tags) => + transformAllDeep(body) + tags.foreach(transformAllDeep) + case Splice(expr) => + transformAllDeep(expr) + case pat @ SplicePattern(body, args) => + transformAllDeep(body) + args.foreach(transformAllDeep) + case MatchTypeTree(bound, selector, cases) => + transformAllDeep(bound) + transformAllDeep(selector) + cases.foreach(transformAllDeep) + case ByNameTypeTree(result) => + transformAllDeep(result) + //case _: InferredTypeTree => // do nothing + //case _: Export => // nothing to do + //case _ if tree.isType => + case _ => + tree - private def pushInBlockTemplatePackageDef(tree: tpd.Block | tpd.Template | tpd.PackageDef)(using Context): Context = - unusedDataApply { ud => - ud.pushScope(UnusedData.ScopeType.fromTree(tree)) - } - ctx + private def traverseAnnotations(sym: Symbol)(using Context): Unit = + for annot <- sym.denot.annotations do + transformAllDeep(annot.tree) - private def popOutBlockTemplatePackageDef()(using Context): Context = - unusedDataApply { ud => - ud.popScope() - } - ctx + // if sym is not an enclosing element, record the reference + def refUsage(sym: Symbol)(using Context): Unit = + if !ctx.outersIterator.exists(cur => cur.owner eq sym) then + refInfos.refs.addOne(sym) - /** - * This traverse is the **main** component of this phase + /** Look up a reference in enclosing contexts to determine whether it was introduced by a definition or import. + * The binding of highest precedence must then be correct. * - * It traverses the tree and gathers the data in the - * corresponding context property + * Unqualified locals and fully qualified globals are neither imported nor in scope; + * e.g., in `scala.Int`, `scala` is in scope for typer, but here we reverse-engineer the attribution. + * For Select, lint does not look up `.scala` (so top-level syms look like magic) but records `scala.Int`. + * For Ident, look-up finds the root import as usual. A competing import is OK because higher precedence. */ - private def traverser = new TreeTraverser: - import tpd.* - import UnusedData.ScopeType - - /* Register every imports, definition and usage */ - override def traverse(tree: tpd.Tree)(using Context): Unit = - val newCtx = if tree.symbol.exists then ctx.withOwner(tree.symbol) else ctx - tree match - case imp: tpd.Import => - unusedDataApply(_.registerImport(imp)) - imp.selectors.filter(_.isGiven).map(_.bound).collect { - case untpd.TypedSplice(tree1) => tree1 - }.foreach(traverse(_)(using newCtx)) - traverseChildren(tree)(using newCtx) - case ident: Ident => - prepareForIdent(ident) - traverseChildren(tree)(using newCtx) - case sel: Select => - prepareForSelect(sel) - traverseChildren(tree)(using newCtx) - case tree: (tpd.Block | tpd.Template | tpd.PackageDef) => - //! DIFFERS FROM MINIPHASE - pushInBlockTemplatePackageDef(tree) - traverseChildren(tree)(using newCtx) - popOutBlockTemplatePackageDef() - case t: tpd.ValDef => - prepareForValDef(t) - traverseChildren(tree)(using newCtx) - transformValDef(t) - case t: tpd.DefDef => - prepareForDefDef(t) - traverseChildren(tree)(using newCtx) - transformDefDef(t) - case t: tpd.TypeDef => - prepareForTypeDef(t) - traverseChildren(tree)(using newCtx) - transformTypeDef(t) - case t: tpd.Bind => - prepareForBind(t) - traverseChildren(tree)(using newCtx) - case t:tpd.Assign => - prepareForAssign(t) - traverseChildren(tree) - case _: tpd.InferredTypeTree => - case t@tpd.RefinedTypeTree(tpt, refinements) => - //! DIFFERS FROM MINIPHASE - typeTraverser(unusedDataApply).traverse(t.tpe) - traverse(tpt)(using newCtx) - case t@tpd.TypeTree() => - //! DIFFERS FROM MINIPHASE - typeTraverser(unusedDataApply).traverse(t.tpe) - traverseChildren(tree)(using newCtx) - case _ => - //! DIFFERS FROM MINIPHASE - traverseChildren(tree)(using newCtx) - end traverse - end traverser - - /** This is a type traverser which catch some special Types not traversed by the term traverser above */ - private def typeTraverser(dt: (UnusedData => Any) => Unit)(using Context) = new TypeTraverser: - override def traverse(tp: Type): Unit = - if tp.typeSymbol.exists then dt(_.registerUsed(tp.typeSymbol, Some(tp.typeSymbol.name))) - tp match - case AnnotatedType(_, annot) => - dt(_.registerUsed(annot.symbol, None)) - traverseChildren(tp) - case _ => - traverseChildren(tp) - - /** This traverse the annotations of the symbol */ - private def traverseAnnotations(sym: Symbol)(using Context): Unit = - sym.denot.annotations.foreach(annot => traverser.traverse(annot.tree)) - - - /** Do the actual reporting given the result of the anaylsis */ - private def reportUnused(res: UnusedData.UnusedResult)(using Context): Unit = - res.warnings.toList.sortBy(_.pos.span.point)(using Ordering[Int]).foreach { s => - s match - case UnusedSymbol(t, _, WarnTypes.Imports) => - report.warning(UnusedSymbolMessage.imports, t) - case UnusedSymbol(t, _, WarnTypes.LocalDefs) => - report.warning(UnusedSymbolMessage.localDefs, t) - case UnusedSymbol(t, _, WarnTypes.ExplicitParams) => - report.warning(UnusedSymbolMessage.explicitParams, t) - case UnusedSymbol(t, _, WarnTypes.ImplicitParams) => - report.warning(UnusedSymbolMessage.implicitParams, t) - case UnusedSymbol(t, _, WarnTypes.PrivateMembers) => - report.warning(UnusedSymbolMessage.privateMembers, t) - case UnusedSymbol(t, _, WarnTypes.PatVars) => - report.warning(UnusedSymbolMessage.patVars, t) - case UnusedSymbol(t, _, WarnTypes.UnsetLocals) => - report.warning("unset local variable, consider using an immutable val instead", t) - case UnusedSymbol(t, _, WarnTypes.UnsetPrivates) => - report.warning("unset private variable, consider using an immutable val instead", t) - } - + def resolveUsage(sym: Symbol, name: Name, prefix: Type)(using Context): Unit = + import PrecedenceLevels.* + + def matchingSelector(info: ImportInfo): ImportSelector | Null = + val qtpe = info.site + def hasAltMember(nm: Name) = qtpe.member(nm).hasAltWith(_.symbol == sym) + def loop(sels: List[ImportSelector]): ImportSelector | Null = sels match + case sel :: sels => + val matches = + if sel.isWildcard then + // the qualifier must have the target symbol as a member + hasAltMember(sym.name) && { + if sel.isGiven then // Further check that the symbol is a given or implicit and conforms to the bound + sym.isOneOf(GivenOrImplicit) + && (sel.bound.isEmpty || sym.info.finalResultType <:< sel.boundTpe) + && (prefix.eq(NoPrefix) || qtpe =:= prefix) + else + !sym.is(Given) // Normal wildcard, check that the symbol is not a given (but can be implicit) + } + else + // if there is an explicit name, it must match + !name.exists(_.toTermName != sel.rename) + && (prefix.eq(NoPrefix) || qtpe =:= prefix) + && (hasAltMember(sel.name) || hasAltMember(sel.name.toTypeName)) + if matches then sel else loop(sels) + case nil => null + loop(info.selectors) + + def checkMember(ctxsym: Symbol): Boolean = + ctxsym.isClass && sym.owner.isClass + && ctxsym.thisType.baseClasses.contains(sym.owner) + && ctxsym.thisType.member(sym.name).hasAltWith(d => d.containsSym(sym) && !name.exists(_ != d.name)) + + // Attempt to cache a result at the given context. Not all contexts bear a cache, including NoContext. + // If there is already any result for the name and prefix, do nothing. + def addCached(where: Context, result: Precedence): Unit = + if where.moreProperties ne null then + where.property(resolvedKey) match + case Some(resolved) => + resolved.record(sym, name, prefix, result) + case none => + + // Avoid spurious NoSymbol and also primary ctors which are never warned about. + if !sym.exists || sym.isPrimaryConstructor then return + + // Find the innermost, highest precedence. Contexts have no nesting levels but assume correctness. + // If the sym is an enclosing definition (the owner of a context), it does not count toward usages. + val isLocal = sym.isLocalToBlock + var candidate: Context = NoContext + var cachePoint: Context = NoContext // last context with Resolved cache + var importer: ImportSelector | Null = null // non-null for import context + var precedence = NoPrecedence // of current resolution + var done = false + var cached = false + val ctxs = ctx.outersIterator + while !done && ctxs.hasNext do + val cur = ctxs.next() + if cur.owner eq sym then + addCached(cachePoint, Definition) + return // found enclosing definition + else if isLocal then + if cur.owner eq sym.owner then + done = true // for local def, just checking that it is not enclosing + else + val cachedPrecedence = + cur.property(resolvedKey) match + case Some(resolved) => + // conservative, cache must be nested below the result context + if precedence.isNone then + cachePoint = cur // no result yet, and future result could be cached here + resolved.hasRecord(sym, name, prefix) + case none => NoPrecedence + cached = !cachedPrecedence.isNone + if cached then + // if prefer cached precedence, then discard previous result + if precedence.weakerThan(cachedPrecedence) then + candidate = NoContext + importer = null + cachePoint = cur // actual cache context + precedence = cachedPrecedence // actual cached precedence + done = true + else if cur.isImportContext then + val sel = matchingSelector(cur.importInfo.nn) + if sel != null then + if cur.importInfo.nn.isRootImport then + if precedence.weakerThan(OtherUnit) then + precedence = OtherUnit + candidate = cur + importer = sel + done = true + else if sel.isWildcard then + if precedence.weakerThan(Wildcard) then + precedence = Wildcard + candidate = cur + importer = sel + else + if precedence.weakerThan(NamedImport) then + precedence = NamedImport + candidate = cur + importer = sel + else if checkMember(cur.owner) then + if sym.srcPos.sourcePos.source == ctx.source then + precedence = Definition + candidate = cur + importer = null // ignore import in same scope; we can't check nesting level + done = true + else if precedence.weakerThan(OtherUnit) then + precedence = OtherUnit + candidate = cur + end while + // record usage and possibly an import + refInfos.refs.addOne(sym) + if candidate != NoContext && candidate.isImportContext && importer != null then + refInfos.sels.put(importer, ()) + // possibly record that we have performed this look-up + // if no result was found, take it as Definition (local or rooted head of fully qualified path) + val adjusted = if precedence.isNone then Definition else precedence + if !cached && (cachePoint ne NoContext) then + addCached(cachePoint, adjusted) + if cachePoint ne ctx then + addCached(ctx, adjusted) // at this ctx, since cachePoint may be far up the outer chain + end resolveUsage end CheckUnused object CheckUnused: - val phaseNamePrefix: String = "checkUnused" - val description: String = "check for unused elements" enum PhaseMode: case Aggregate case Report - private enum WarnTypes: - case Imports - case LocalDefs - case ExplicitParams - case ImplicitParams - case PrivateMembers - case PatVars - case UnsetLocals - case UnsetPrivates - - /** - * The key used to retrieve the "unused entity" analysis metadata, - * from the compilation `Context` - */ - private val _key = Property.StickyKey[UnusedData] + val refInfosKey = Property.StickyKey[RefInfos] - val OriginalName = Property.StickyKey[Name] + val resolvedKey = Property.Key[Resolved] - class PostTyper extends CheckUnused(PhaseMode.Aggregate, "PostTyper", _key) + inline def refInfos(using Context): RefInfos = ctx.property(refInfosKey).get - class PostInlining extends CheckUnused(PhaseMode.Report, "PostInlining", _key) + inline def resolved(using Context): Resolved = + ctx.property(resolvedKey) match + case Some(res) => res + case _ => throw new MatchError("no Resolved for context") - /** - * A stateful class gathering the infos on : - * - imports - * - definitions - * - usage - */ - private class UnusedData: - import collection.mutable.{Set => MutSet, Map => MutMap, Stack => MutStack, ListBuffer => MutList} - import UnusedData.* - - /** The current scope during the tree traversal */ - val currScopeType: MutStack[ScopeType] = MutStack(ScopeType.Other) - - var unusedAggregate: Option[UnusedResult] = None - - /* IMPORTS */ - private val impInScope = MutStack(MutList[ImportSelectorData]()) - /** - * We store the symbol along with their accessibility without import. - * Accessibility to their definition in outer context/scope - * - * See the `isAccessibleAsIdent` extension method below in the file - */ - private val usedInScope = MutStack(MutSet[(Symbol, Option[Name], Boolean)]()) - private val usedInPosition = MutMap.empty[Name, MutSet[Symbol]] - /* unused import collected during traversal */ - private val unusedImport = MutList.empty[ImportSelectorData] - - /* LOCAL DEF OR VAL / Private Def or Val / Pattern variables */ - private val localDefInScope = MutList.empty[tpd.MemberDef] - private val privateDefInScope = MutList.empty[tpd.MemberDef] - private val explicitParamInScope = MutList.empty[tpd.MemberDef] - private val implicitParamInScope = MutList.empty[tpd.MemberDef] - private val patVarsInScope = MutList.empty[tpd.Bind] - - /** All variables sets*/ - private val setVars = MutSet[Symbol]() - - /** All used symbols */ - private val usedDef = MutSet[Symbol]() - /** Do not register as used */ - private val doNotRegister = MutSet[Symbol]() - - /** Trivial definitions, avoid registering params */ - private val trivialDefs = MutSet[Symbol]() - - private val paramsToSkip = MutSet[Symbol]() - - - def finishAggregation(using Context)(): Unit = - val unusedInThisStage = this.getUnused - this.unusedAggregate match { - case None => - this.unusedAggregate = Some(unusedInThisStage) - case Some(prevUnused) => - val intersection = unusedInThisStage.warnings.intersect(prevUnused.warnings) - this.unusedAggregate = Some(UnusedResult(intersection)) - } - - - /** - * Register a found (used) symbol along with its name - * - * The optional name will be used to target the right import - * as the same element can be imported with different renaming - */ - def registerUsed(sym: Symbol, name: Option[Name], includeForImport: Boolean = true, isDerived: Boolean = false)(using Context): Unit = - if sym.exists && !isConstructorOfSynth(sym) && !doNotRegister(sym) then - if sym.isConstructor then - registerUsed(sym.owner, None, includeForImport) // constructor are "implicitly" imported with the class - else - // If the symbol is accessible in this scope without an import, do not register it for unused import analysis - val includeForImport1 = - includeForImport - && (name.exists(_.toTermName != sym.name.toTermName) || !sym.isAccessibleAsIdent) - - def addIfExists(sym: Symbol): Unit = - if sym.exists then - usedDef += sym - if includeForImport1 then - usedInScope.top += ((sym, name, isDerived)) - addIfExists(sym) - addIfExists(sym.companionModule) - addIfExists(sym.companionClass) - if sym.sourcePos.exists then - for n <- name do - usedInPosition.getOrElseUpdate(n, MutSet.empty) += sym - - /** Register a symbol that should be ignored */ - def addIgnoredUsage(sym: Symbol)(using Context): Unit = - doNotRegister ++= sym.everySymbol - - /** Remove a symbol that shouldn't be ignored anymore */ - def removeIgnoredUsage(sym: Symbol)(using Context): Unit = - doNotRegister --= sym.everySymbol - - def addIgnoredParam(sym: Symbol)(using Context): Unit = - paramsToSkip += sym - - /** Register an import */ - def registerImport(imp: tpd.Import)(using Context): Unit = - if - !tpd.languageImport(imp.expr).nonEmpty - && !imp.isGeneratedByEnum - && !isTransparentAndInline(imp) - && currScopeType.top != ScopeType.ReplWrapper // #18383 Do not report top-level import's in the repl as unused - then - val qualTpe = imp.expr.tpe - - // Put wildcard imports at the end, because they have lower priority within one Import - val reorderdSelectors = - val (wildcardSels, nonWildcardSels) = imp.selectors.partition(_.isWildcard) - nonWildcardSels ::: wildcardSels - - val excludedMembers: mutable.Set[TermName] = mutable.Set.empty - - val newDataInScope = - for sel <- reorderdSelectors yield - val data = new ImportSelectorData(qualTpe, sel) - if shouldSelectorBeReported(imp, sel) || isImportExclusion(sel) || isImportIgnored(imp, sel) then - // Immediately mark the selector as used - data.markUsed() - if isImportExclusion(sel) then - excludedMembers += sel.name - if sel.isWildcard && excludedMembers.nonEmpty then - // mark excluded members for the wildcard import - data.markExcluded(excludedMembers.toSet) - data - impInScope.top.appendAll(newDataInScope) - end registerImport - - /** Register (or not) some `val` or `def` according to the context, scope and flags */ - def registerDef(memDef: tpd.MemberDef)(using Context): Unit = - if memDef.isValidMemberDef && !isDefIgnored(memDef) then - if memDef.isValidParam then - if memDef.symbol.isOneOf(GivenOrImplicit) then - if !paramsToSkip.contains(memDef.symbol) then - implicitParamInScope += memDef - else if !paramsToSkip.contains(memDef.symbol) then - explicitParamInScope += memDef - else if currScopeType.top == ScopeType.Local then - localDefInScope += memDef - else if memDef.shouldReportPrivateDef then - privateDefInScope += memDef - - /** Register pattern variable */ - def registerPatVar(patvar: tpd.Bind)(using Context): Unit = - if !patvar.symbol.isUnusedAnnot then - patVarsInScope += patvar - - /** enter a new scope */ - def pushScope(newScopeType: ScopeType): Unit = - // unused imports : - currScopeType.push(newScopeType) - impInScope.push(MutList()) - usedInScope.push(MutSet()) - - def registerSetVar(sym: Symbol): Unit = - setVars += sym - - /** - * leave the current scope and do : - * - * - If there are imports in this scope check for unused ones - */ - def popScope()(using Context): Unit = - currScopeType.pop() - val usedInfos = usedInScope.pop() - val selDatas = impInScope.pop() - - for usedInfo <- usedInfos do - val (sym, optName, isDerived) = usedInfo - val usedData = selDatas.find { selData => - sym.isInImport(selData, optName, isDerived) - } - usedData match - case Some(data) => - data.markUsed() - case None => - // Propagate the symbol one level up - if usedInScope.nonEmpty then - usedInScope.top += usedInfo - end for // each in `used` - - for selData <- selDatas do - if !selData.isUsed then - unusedImport += selData - end popScope - - /** - * Leave the scope and return a `List` of unused `ImportSelector`s - * - * The given `List` is sorted by line and then column of the position - */ + /** Attachment holding the name of an Ident as written by the user. */ + val OriginalName = Property.StickyKey[Name] - def getUnused(using Context): UnusedResult = - popScope() + /** Suppress warning in a tree, such as a patvar name allowed by special convention. */ + val NoWarn = Property.StickyKey[Unit] - def isUsedInPosition(name: Name, span: Span): Boolean = - usedInPosition.get(name) match - case Some(syms) => syms.exists(sym => span.contains(sym.span)) - case None => false + /** Ignore reference. */ + val Ignore = Property.StickyKey[Unit] - val sortedImp = - if ctx.settings.WunusedHas.imports || ctx.settings.WunusedHas.strictNoImplicitWarn then - unusedImport.toList - .map(d => UnusedSymbol(d.selector.srcPos, d.selector.name, WarnTypes.Imports)) - else - Nil - // Partition to extract unset local variables from usedLocalDefs - val (usedLocalDefs, unusedLocalDefs) = - if ctx.settings.WunusedHas.locals then - localDefInScope.toList.partition(d => d.symbol.usedDefContains) - else - (Nil, Nil) - val sortedLocalDefs = - unusedLocalDefs - .filterNot(d => isUsedInPosition(d.symbol.name, d.span)) - .filterNot(d => containsSyntheticSuffix(d.symbol)) - .map(d => UnusedSymbol(d.namePos, d.name, WarnTypes.LocalDefs)) - val unsetLocalDefs = usedLocalDefs.filter(isUnsetVarDef).map(d => UnusedSymbol(d.namePos, d.name, WarnTypes.UnsetLocals)).toList - - val sortedExplicitParams = - if ctx.settings.WunusedHas.explicits then - explicitParamInScope.toList - .filterNot(d => d.symbol.usedDefContains) - .filterNot(d => isUsedInPosition(d.symbol.name, d.span)) - .filterNot(d => containsSyntheticSuffix(d.symbol)) - .map(d => UnusedSymbol(d.namePos, d.name, WarnTypes.ExplicitParams)) - else - Nil - val sortedImplicitParams = - if ctx.settings.WunusedHas.implicits then - implicitParamInScope.toList - .filterNot(d => d.symbol.usedDefContains) - .filterNot(d => containsSyntheticSuffix(d.symbol)) - .map(d => UnusedSymbol(d.namePos, d.name, WarnTypes.ImplicitParams)) - else - Nil - // Partition to extract unset private variables from usedPrivates - val (usedPrivates, unusedPrivates) = - if ctx.settings.WunusedHas.privates then - privateDefInScope.toList.partition(d => d.symbol.usedDefContains) - else - (Nil, Nil) - val sortedPrivateDefs = unusedPrivates.filterNot(d => containsSyntheticSuffix(d.symbol)).map(d => UnusedSymbol(d.namePos, d.name, WarnTypes.PrivateMembers)) - val unsetPrivateDefs = usedPrivates.filter(isUnsetVarDef).map(d => UnusedSymbol(d.namePos, d.name, WarnTypes.UnsetPrivates)) - val sortedPatVars = - if ctx.settings.WunusedHas.patvars then - patVarsInScope.toList - .filterNot(d => d.symbol.usedDefContains) - .filterNot(d => containsSyntheticSuffix(d.symbol)) - .filterNot(d => isUsedInPosition(d.symbol.name, d.span)) - .map(d => UnusedSymbol(d.namePos, d.name, WarnTypes.PatVars)) - else - Nil - val warnings = - sortedImp ::: - sortedLocalDefs ::: - sortedExplicitParams ::: - sortedImplicitParams ::: - sortedPrivateDefs ::: - sortedPatVars ::: - unsetLocalDefs ::: - unsetPrivateDefs - UnusedResult(warnings.toSet) - end getUnused - //============================ HELPERS ==================================== - - - /** - * Checks if import selects a def that is transparent and inline - */ - private def isTransparentAndInline(imp: tpd.Import)(using Context): Boolean = - imp.selectors.exists { sel => - val qual = imp.expr - val importedMembers = qual.tpe.member(sel.name).alternatives.map(_.symbol) - importedMembers.exists(s => s.is(Transparent) && s.is(Inline)) - } - - /** - * Heuristic to detect synthetic suffixes in names of symbols - */ - private def containsSyntheticSuffix(symbol: Symbol)(using Context): Boolean = - symbol.name.mangledString.contains("$") - - /** - * Is the constructor of synthetic package object - * Should be ignored as it is always imported/used in package - * Trigger false negative on used import - * - * Without this check example: - * - * --- WITH PACKAGE : WRONG --- - * {{{ - * package a: - * val x: Int = 0 - * package b: - * import a.* // no warning - * }}} - * --- WITH OBJECT : OK --- - * {{{ - * object a: - * val x: Int = 0 - * object b: - * import a.* // unused warning - * }}} - */ - private def isConstructorOfSynth(sym: Symbol)(using Context): Boolean = - sym.exists && sym.isConstructor && sym.owner.isPackageObject && sym.owner.is(Synthetic) + class PostTyper extends CheckUnused(PhaseMode.Aggregate, "PostTyper") - /** - * This is used to avoid reporting the parameters of the synthetic main method - * generated by `@main` - */ - private def isSyntheticMainParam(sym: Symbol)(using Context): Boolean = - sym.exists && ctx.platform.isMainMethod(sym.owner) && sym.owner.is(Synthetic) + class PostInlining extends CheckUnused(PhaseMode.Report, "PostInlining") - /** - * This is used to ignore exclusion imports (i.e. import `qual`.{`member` => _}) + class RefInfos: + val defs = mutable.Set.empty[(Symbol, SrcPos)] // definitions + val pats = mutable.Set.empty[(Symbol, SrcPos)] // pattern variables + val refs = mutable.Set.empty[Symbol] // references + val asss = mutable.Set.empty[Symbol] // targets of assignment + val skip = mutable.Set.empty[Symbol] // methods to skip (don't warn about their params) + val imps = new IdentityHashMap[Import, Unit] // imports + val sels = new IdentityHashMap[ImportSelector, Unit] // matched selectors + def register(tree: Tree)(using Context): Unit = if inlined.isEmpty then + tree match + case imp: Import => + if inliners == 0 + && languageImport(imp.expr).isEmpty + && !imp.isGeneratedByEnum + && !ctx.outer.owner.name.isReplWrapperName + then + imps.put(imp, ()) + case tree: Bind => + if !tree.name.isInstanceOf[DerivedName] && !tree.name.is(WildcardParamName) && !tree.hasAttachment(NoWarn) then + pats.addOne((tree.symbol, tree.namePos)) + case tree: ValDef if tree.hasAttachment(PatternVar) => + if !tree.name.isInstanceOf[DerivedName] then + pats.addOne((tree.symbol, tree.namePos)) + case tree: NamedDefTree => + if (tree.symbol ne NoSymbol) && !tree.name.isWildcard then + defs.addOne((tree.symbol, tree.namePos)) + case _ => + //println(s"OTHER ${tree.symbol}") + if tree.symbol ne NoSymbol then + defs.addOne((tree.symbol, tree.srcPos)) + + val inlined = Stack.empty[SrcPos] // enclosing call.srcPos of inlined code (expansions) + var inliners = 0 // depth of inline def (not inlined yet) + end RefInfos + + // Symbols already resolved in the given Context (with name and prefix of lookup). + class Resolved: + import PrecedenceLevels.* + private val seen = mutable.Map.empty[Symbol, List[(Name, Type, Precedence)]].withDefaultValue(Nil) + // if a result has been recorded, return it; otherwise, NoPrecedence. + def hasRecord(symbol: Symbol, name: Name, prefix: Type)(using Context): Precedence = + seen(symbol).find((n, p, _) => n == name && p =:= prefix) match + case Some((_, _, r)) => r + case none => NoPrecedence + // "record" the look-up result, if there is not already a result for the name and prefix. + def record(symbol: Symbol, name: Name, prefix: Type, result: Precedence)(using Context): Unit = + require(NoPrecedence.weakerThan(result)) + seen.updateWith(symbol): + case svs @ Some(vs) => + if vs.exists((n, p, _) => n == name && p =:= prefix) then svs + else Some((name, prefix, result) :: vs) + case none => Some((name, prefix, result) :: Nil) + + // Names are resolved by definitions and imports, which have four precedence levels: + object PrecedenceLevels: + opaque type Precedence = Int + inline def NoPrecedence: Precedence = 5 + inline def OtherUnit: Precedence = 4 // root import or def from another compilation unit via enclosing package + inline def Wildcard: Precedence = 3 // wildcard import + inline def NamedImport: Precedence = 2 // specific import + inline def Definition: Precedence = 1 // def from this compilation unit + extension (p: Precedence) + inline def weakerThan(q: Precedence): Boolean = p > q + inline def isNone: Boolean = p == NoPrecedence + + def reportUnused()(using Context): Unit = + for (msg, pos, origin) <- warnings do + if origin.isEmpty then report.warning(msg, pos) + else report.warning(msg, pos, origin) + msg.actions.headOption.foreach(Rewrites.applyAction) + + type MessageInfo = (UnusedSymbol, SrcPos, String) // string is origin or empty + + def warnings(using Context): Array[MessageInfo] = + val actionable = ctx.settings.rewrite.value.nonEmpty + val warnings = ArrayBuilder.make[MessageInfo] + def warnAt(pos: SrcPos)(msg: UnusedSymbol, origin: String = ""): Unit = warnings.addOne((msg, pos, origin)) + val infos = refInfos + + def checkUnassigned(sym: Symbol, pos: SrcPos) = + if sym.isLocalToBlock then + if ctx.settings.WunusedHas.locals && sym.is(Mutable) && !infos.asss(sym) then + warnAt(pos)(UnusedSymbol.unsetLocals) + else if ctx.settings.WunusedHas.privates && sym.isAllOf(Private | Mutable) && !infos.asss(sym) then + warnAt(pos)(UnusedSymbol.unsetPrivates) + + def checkPrivate(sym: Symbol, pos: SrcPos) = + if ctx.settings.WunusedHas.privates + && !sym.isPrimaryConstructor + && sym.is(Private, butNot = SelfName | Synthetic | CaseAccessor) + && !sym.isSerializationSupport + && !(sym.is(Mutable) && sym.isSetter && sym.owner.is(Trait)) // tracks sym.underlyingSymbol sibling getter + then + warnAt(pos)(UnusedSymbol.privateMembers) + + def checkParam(sym: Symbol, pos: SrcPos) = + val m = sym.owner + def allowed = + val dd = defn + m.isDeprecated + || m.is(Synthetic) && !m.isAnonymousFunction + || m.hasAnnotation(defn.UnusedAnnot) // param of unused method + || sym.info.isSingleton + || m.isConstructor && m.owner.thisType.baseClasses.contains(defn.AnnotationClass) + def checkExplicit(): Unit = + // A class param is unused if its param accessor is unused. + // (The class param is not assigned to a field until constructors.) + // A local param accessor warns as a param; a private accessor as a private member. + // Avoid warning for case class elements because they are aliased via unapply. + if m.isPrimaryConstructor then + val alias = m.owner.info.member(sym.name) + if alias.exists then + val aliasSym = alias.symbol + if aliasSym.isAllOf(PrivateParamAccessor, butNot = CaseAccessor) && !infos.refs(alias.symbol) then + if aliasSym.is(Local) then + if ctx.settings.WunusedHas.explicits then + warnAt(pos)(UnusedSymbol.explicitParams) + else + if ctx.settings.WunusedHas.privates then + warnAt(pos)(UnusedSymbol.privateMembers) + else if ctx.settings.WunusedHas.explicits + && !sym.is(Synthetic) // param to setter is unused bc there is no field yet + && !(sym.owner.is(ExtensionMethod) && { + m.paramSymss.dropWhile(_.exists(_.isTypeParam)) match + case (h :: Nil) :: Nil => h == sym // param is the extended receiver + case _ => false + }) + && !sym.name.isInstanceOf[DerivedName] + && !ctx.platform.isMainMethod(m) + then + warnAt(pos)(UnusedSymbol.explicitParams) + end checkExplicit + // begin + if !infos.skip(m) + && !allowed + then + checkExplicit() + end checkParam + + def checkImplicit(sym: Symbol, pos: SrcPos) = + val m = sym.owner + def allowed = + val dd = defn + m.isDeprecated + || m.is(Synthetic) + || sym.name.is(ContextFunctionParamName) // a ubiquitous parameter + || sym.name.is(ContextBoundParamName) && sym.info.typeSymbol.isMarkerTrait // a ubiquitous parameter + || m.hasAnnotation(dd.UnusedAnnot) // param of unused method + || sym.info.typeSymbol.match // more ubiquity + case dd.DummyImplicitClass | dd.SubTypeClass | dd.SameTypeClass => true + case _ => false + || sym.info.isSingleton // DSL friendly + || sym.isCanEqual + || sym.info.typeSymbol.hasAnnotation(dd.LanguageFeatureMetaAnnot) + || sym.info.isInstanceOf[RefinedType] // can't be expressed as a context bound + if ctx.settings.WunusedHas.implicits + && !infos.skip(m) + && !allowed + then + if m.isPrimaryConstructor then + val alias = m.owner.info.member(sym.name) + if alias.exists then + val aliasSym = alias.symbol + if aliasSym.is(ParamAccessor) && !infos.refs(alias.symbol) then + warnAt(pos)(UnusedSymbol.implicitParams) + else + warnAt(pos)(UnusedSymbol.implicitParams) + + def checkLocal(sym: Symbol, pos: SrcPos) = + if ctx.settings.WunusedHas.locals + && !sym.is(InlineProxy) + && !sym.isCanEqual + then + warnAt(pos)(UnusedSymbol.localDefs) + + def checkPatvars() = + // convert the one non-synthetic span so all are comparable + def uniformPos(sym: Symbol, pos: SrcPos): SrcPos = + if pos.span.isSynthetic then pos else pos.sourcePos.withSpan(pos.span.toSynthetic) + // patvars in for comprehensions share the pos of where the name was introduced + val byPos = infos.pats.groupMap(uniformPos(_, _))((sym, pos) => sym) + for (pos, syms) <- byPos if !syms.exists(_.hasAnnotation(defn.UnusedAnnot)) do + if !syms.exists(infos.refs(_)) then + if !syms.exists(v => !v.isLocal && !v.is(Private)) then + warnAt(pos)(UnusedSymbol.patVars) + else if syms.exists(_.is(Mutable)) then // check unassigned var + val sym = // recover the original + if syms.size == 1 then syms.head + else infos.pats.find((s, p) => syms.contains(s) && !p.span.isSynthetic).map(_._1).getOrElse(syms.head) + if sym.is(Mutable) && !infos.asss(sym) then + if sym.isLocalToBlock then + warnAt(pos)(UnusedSymbol.unsetLocals) + else if sym.is(Private) then + warnAt(pos)(UnusedSymbol.unsetPrivates) + + def checkImports() = + // TODO check for unused masking import + import scala.jdk.CollectionConverters.given + import Rewrites.ActionPatch + type ImpSel = (Import, ImportSelector) + def isUsable(imp: Import, sel: ImportSelector): Boolean = + sel.isImportExclusion || infos.sels.containsKey(sel) || imp.isLoose(sel) + def warnImport(warnable: ImpSel, actions: List[CodeAction] = Nil): Unit = + val (imp, sel) = warnable + val msg = UnusedSymbol.imports(actions) + // example collection.mutable.{Map as MutMap} + val origin = cpy.Import(imp)(imp.expr, List(sel)).show(using ctx.withoutColors).stripPrefix("import ") + warnAt(sel.srcPos)(msg, origin) + + if !actionable then + for imp <- infos.imps.keySet.nn.asScala; sel <- imp.selectors if !isUsable(imp, sel) do + warnImport(imp -> sel) + else + // If the rest of the line is blank, include it in the final edit position. (Delete trailing whitespace.) + // If for deletion, and the prefix of the line is also blank, then include that, too. (Del blank line.) + def editPosAt(srcPos: SrcPos, forDeletion: Boolean): SrcPos = + val start = srcPos.span.start + val end = srcPos.span.end + val content = srcPos.sourcePos.source.content() + val prev = content.lastIndexWhere(c => !isWhitespace(c), end = start - 1) + val emptyLeft = prev < 0 || isLineBreakChar(content(prev)) + val next = content.indexWhere(c => !isWhitespace(c), from = end) + val emptyRight = next < 0 || isLineBreakChar(content(next)) + val deleteLine = emptyLeft && emptyRight && forDeletion + val bump = if (deleteLine) 1 else 0 // todo improve to include offset of next line, endline + 1 + val p0 = srcPos.span + val p1 = if (next >= 0 && emptyRight) p0.withEnd(next + bump) else p0 + val p2 = if (deleteLine) p1.withStart(prev + 1) else p1 + srcPos.sourcePos.withSpan(p2) + def actionsOf(actions: (SrcPos, String)*): List[CodeAction] = + val patches = actions.map((srcPos, replacement) => ActionPatch(srcPos.sourcePos, replacement)).toList + List(CodeAction(title = "unused import", description = Some("remove import"), patches)) + def replace(editPos: SrcPos)(replacement: String): List[CodeAction] = actionsOf(editPos -> replacement) + def deletion(editPos: SrcPos): List[CodeAction] = actionsOf(editPos -> "") + def textFor(impsel: ImpSel): String = + val (imp, sel) = impsel + val content = imp.srcPos.sourcePos.source.content() + def textAt(pos: SrcPos) = String(content.slice(pos.span.start, pos.span.end)) + val qual = textAt(imp.expr.srcPos) // keep original + val selector = textAt(sel.srcPos) // keep original + s"$qual.$selector" // don't succumb to vagaries of show + // begin actionable + val sortedImps = infos.imps.keySet.nn.asScala.toArray.sortBy(_.srcPos.span.point) // sorted by pos + var index = 0 + while index < sortedImps.length do + val nextImport = sortedImps.indexSatisfying(from = index + 1)(_.isPrimaryClause) // next import statement + if sortedImps.indexSatisfying(from = index, until = nextImport): imp => + imp.selectors.exists(!isUsable(imp, _)) // check if any selector in statement was unused + < nextImport then + // if no usable selectors in the import statement, delete it entirely. + // if there is exactly one usable selector, then replace with just that selector (i.e., format it). + // else for each clause, delete it or format one selector or delete unused selectors. + // To delete a comma separated item, delete start-to-start, but for last item delete a preceding comma. + // Reminder that first clause span includes the keyword, so delete point-to-start instead. + val existing = sortedImps.slice(index, nextImport) + val (keeping, deleting) = existing.iterator.flatMap(imp => imp.selectors.map(imp -> _)).toList + .partition(isUsable(_, _)) + if keeping.isEmpty then + val editPos = existing.head.srcPos.sourcePos.withSpan: + Span(start = existing.head.srcPos.span.start, end = existing.last.srcPos.span.end) + deleting.init.foreach(warnImport(_)) + warnImport(deleting.last, deletion(editPosAt(editPos, forDeletion = true))) + else if keeping.lengthIs == 1 then + val editPos = existing.head.srcPos.sourcePos.withSpan: + Span(start = existing.head.srcPos.span.start, end = existing.last.srcPos.span.end) + deleting.init.foreach(warnImport(_)) + val text = s"import ${textFor(keeping.head)}" + warnImport(deleting.last, replace(editPosAt(editPos, forDeletion = false))(text)) + else + val lostClauses = existing.iterator.filter(imp => !keeping.exists((i, _) => imp eq i)).toList + for imp <- lostClauses do + val actions = + if imp == existing.last then + val content = imp.srcPos.sourcePos.source.content() + val prev = existing.lastIndexWhere(i0 => keeping.exists((i, _) => i == i0)) + val comma = content.indexOf(',', from = existing(prev).srcPos.span.end) + val commaPos = imp.srcPos.sourcePos.withSpan: + Span(start = comma, end = existing(prev + 1).srcPos.span.start) + val srcPos = imp.srcPos + val editPos = srcPos.sourcePos.withSpan: // exclude keyword + srcPos.span.withStart(srcPos.span.point) + actionsOf(commaPos -> "", editPos -> "") + else + val impIndex = existing.indexOf(imp) + val editPos = imp.srcPos.sourcePos.withSpan: // exclude keyword + Span(start = imp.srcPos.span.point, end = existing(impIndex + 1).srcPos.span.start) + deletion(editPos) + imp.selectors.init.foreach(sel => warnImport(imp -> sel)) + warnImport(imp -> imp.selectors.last, actions) + val singletons = existing.iterator.filter(imp => keeping.count((i, _) => imp eq i) == 1).toList + var seen = List.empty[Import] + for impsel <- deleting do + val (imp, sel) = impsel + if singletons.contains(imp) then + if seen.contains(imp) then + warnImport(impsel) + else + seen ::= imp + val editPos = imp.srcPos.sourcePos.withSpan: + Span(start = imp.srcPos.span.point, end = imp.srcPos.span.end) // exclude keyword + val text = textFor(keeping.find((i, _) => imp eq i).get) + warnImport(impsel, replace(editPosAt(editPos, forDeletion = false))(text)) + else if !lostClauses.contains(imp) then + val actions = + if sel == imp.selectors.last then + val content = sel.srcPos.sourcePos.source.content() + val prev = imp.selectors.lastIndexWhere(s0 => keeping.exists((_, s) => s == s0)) + val comma = content.indexOf(',', from = imp.selectors(prev).srcPos.span.end) + val commaPos = sel.srcPos.sourcePos.withSpan: + Span(start = comma, end = imp.selectors(prev + 1).srcPos.span.start) + val editPos = sel.srcPos + actionsOf(commaPos -> "", editPos -> "") + else + val selIndex = imp.selectors.indexOf(sel) + val editPos = sel.srcPos.sourcePos.withSpan: + sel.srcPos.span.withEnd(imp.selectors(selIndex + 1).srcPos.span.start) + deletion(editPos) + warnImport(impsel, actions) + end if + index = nextImport + end while + + // begin + for (sym, pos) <- infos.defs.iterator if !sym.hasAnnotation(defn.UnusedAnnot) do + if infos.refs(sym) then + checkUnassigned(sym, pos) + else if sym.is(Private, butNot = ParamAccessor) then + checkPrivate(sym, pos) + else if sym.is(Param, butNot = Given | Implicit) then + checkParam(sym, pos) + else if sym.is(Param) then // Given | Implicit + checkImplicit(sym, pos) + else if sym.isLocalToBlock then + checkLocal(sym, pos) + + if ctx.settings.WunusedHas.patvars then + checkPatvars() + + if ctx.settings.WunusedHas.imports || ctx.settings.WunusedHas.strictNoImplicitWarn then + checkImports() + + warnings.result().sortBy(_._2.span.point) + end warnings + + // Specific exclusions + def ignoreTree(tree: Tree): Boolean = + tree.hasAttachment(ForArtifact) || tree.hasAttachment(Ignore) + + // The RHS of a def is too trivial to warn about unused params, e.g. def f(x: Int) = ??? + def isUnconsuming(rhs: Tree)(using Context): Boolean = + rhs.symbol == defn.Predef_undefined + || rhs.tpe =:= defn.NothingType // compiletime.error + || rhs.isInstanceOf[Literal] // 42 + || rhs.tpe.match + case ConstantType(_) => true + case tp: TermRef => tp.underlying.classSymbol.is(Module) // Scala 2 SingleType + case _ => false + //|| isPurePath(rhs) // a bit strong + || rhs.match + case Block((dd @ DefDef(anonfun, paramss, _, _)) :: Nil, Closure(Nil, Ident(nm), _)) => + anonfun == nm // isAnonymousFunctionName(anonfun) + && paramss.match + case (ValDef(contextual, _, _) :: Nil) :: Nil => + contextual.is(ContextFunctionParamName) + && isUnconsuming(dd.rhs) // rhs was wrapped in a context function + case _ => false + case Block(Nil, Literal(u)) => u.tpe =:= defn.UnitType // def f(x: X) = {} + case This(_) => true + case Ident(_) => rhs.symbol.is(ParamAccessor) + case Typed(rhs, _) => isUnconsuming(rhs) + case _ => false + + def allowVariableBindings(ok: List[Name], args: List[Tree]): Unit = + ok.zip(args).foreach: + case (param, arg @ Bind(p, _)) if param == p => arg.withAttachment(NoWarn, ()) + case _ => + + // NoWarn Binds if the name matches a "canonical" name, e.g. case element name + val nowarner = new TreeTraverser: + def traverse(tree: Tree)(using Context) = tree match + case UnApply(fun, _, args) => + val unapplied = tree.tpe.finalResultType.dealias.typeSymbol + if unapplied.is(CaseClass) then + allowVariableBindings(unapplied.primaryConstructor.info.firstParamNames, args) + else if fun.symbol == defn.PairClass_unapply then + val ok = fun.symbol.info match + case PolyType(tycon, MethodTpe(_, _, AppliedType(_, tprefs))) => + tprefs.collect: + case ref: TypeParamRef => termName(ref.binder.paramNames(ref.paramNum).toString.toLowerCase.nn) + case _ => Nil + allowVariableBindings(ok, args) + else if fun.symbol == defn.TypeTest_unapply then + () // just recurse into args + else + if unapplied.exists && unapplied.owner == defn.Quotes_reflectModule then + // cheapy search for parameter names via java reflection of Trees + // in lieu of drilling into requiredClass("scala.quoted.runtime.impl.QuotesImpl") + // ...member("reflect")...member(unapplied.name.toTypeName) + // with aliases into requiredModule("dotty.tools.dotc.ast.tpd") + val implName = s"dotty.tools.dotc.ast.Trees$$${unapplied.name}" + try + import scala.language.unsafeNulls + val clz = Class.forName(implName) // TODO improve to use class path or reflect + val ok = clz.getConstructors.head.getParameters.map(p => termName(p.getName)).toList.init + allowVariableBindings(ok, args) + catch case _: ClassNotFoundException => () + args.foreach(traverse) + case tree => traverseChildren(tree) + + extension (nm: Name) + inline def exists(p: Name => Boolean): Boolean = nm.ne(nme.NO_NAME) && p(nm) + inline def isWildcard: Boolean = nm == nme.WILDCARD || nm.is(WildcardParamName) + + extension (tp: Type) + def importPrefix(using Context): Type = tp match + case tp: NamedType => tp.prefix + case tp: ClassInfo => tp.prefix + case tp: TypeProxy => tp.superType.normalizedPrefix + case _ => NoType + def underlyingPrefix(using Context): Type = tp match + case tp: NamedType => tp.prefix + case tp: ClassInfo => tp.prefix + case tp: TypeProxy => tp.underlying.underlyingPrefix + case _ => NoType + def skipPackageObject(using Context): Type = + if tp.typeSymbol.isPackageObject then tp.underlyingPrefix else tp + def underlying(using Context): Type = tp match + case tp: TypeProxy => tp.underlying + case _ => tp + + private val serializationNames: Set[TermName] = + Set("readResolve", "readObject", "readObjectNoData", "writeObject", "writeReplace").map(termName(_)) + + extension (sym: Symbol) + def isSerializationSupport(using Context): Boolean = + sym.is(Method) && serializationNames(sym.name.toTermName) && sym.owner.isClass + && sym.owner.derivesFrom(defn.JavaSerializableClass) + def isCanEqual(using Context): Boolean = + sym.isOneOf(GivenOrImplicit) && sym.info.finalResultType.baseClasses.exists(_.derivesFrom(defn.CanEqualClass)) + def isMarkerTrait(using Context): Boolean = + sym.isClass && sym.info.allMembers.forall: d => + val m = d.symbol + !m.isTerm || m.isSelfSym || m.is(Method) && (m.owner == defn.AnyClass || m.owner == defn.ObjectClass) + + extension (sel: ImportSelector) + def boundTpe: Type = sel.bound match + case untpd.TypedSplice(tree) => tree.tpe + case _ => NoType + /** This is used to ignore exclusion imports of the form import `qual.member as _` + * because `sel.isUnimport` is too broad for old style `import concurrent._`. */ - private def isImportExclusion(sel: ImportSelector): Boolean = sel.renamed match - case untpd.Ident(name) => name == StdNames.nme.WILDCARD + def isImportExclusion: Boolean = sel.renamed match + case untpd.Ident(nme.WILDCARD) => true case _ => false - /** - * If -Wunused:strict-no-implicit-warn import and this import selector could potentially import implicit. - * return true - */ - private def shouldSelectorBeReported(imp: tpd.Import, sel: ImportSelector)(using Context): Boolean = - ctx.settings.WunusedHas.strictNoImplicitWarn && ( - sel.isWildcard || - imp.expr.tpe.member(sel.name.toTermName).alternatives.exists(_.symbol.isOneOf(GivenOrImplicit)) || - imp.expr.tpe.member(sel.name.toTypeName).alternatives.exists(_.symbol.isOneOf(GivenOrImplicit)) - ) - - /** - * Ignore CanEqual imports - */ - private def isImportIgnored(imp: tpd.Import, sel: ImportSelector)(using Context): Boolean = - (sel.isWildcard && sel.isGiven && imp.expr.tpe.allMembers.exists(p => p.symbol.typeRef.baseClasses.exists(_.derivesFrom(defn.CanEqualClass)) && p.symbol.isOneOf(GivenOrImplicit))) || - (imp.expr.tpe.member(sel.name.toTermName).alternatives - .exists(p => p.symbol.isOneOf(GivenOrImplicit) && p.symbol.typeRef.baseClasses.exists(_.derivesFrom(defn.CanEqualClass)))) + extension (imp: Import) + /** Is it the first import clause in a statement? `a.x` in `import a.x, b.{y, z}` */ + def isPrimaryClause(using Context): Boolean = + val span = imp.srcPos.span + span.start != span.point // primary clause starts at `import` keyword - /** - * Ignore definitions of CanEqual given - */ - private def isDefIgnored(memDef: tpd.MemberDef)(using Context): Boolean = - memDef.symbol.isOneOf(GivenOrImplicit) && memDef.symbol.typeRef.baseClasses.exists(_.derivesFrom(defn.CanEqualClass)) - - extension (tree: ImportSelector) - def boundTpe: Type = tree.bound match { - case untpd.TypedSplice(tree1) => tree1.tpe - case _ => NoType - } - - extension (sym: Symbol) - /** is accessible without import in current context */ - private def isAccessibleAsIdent(using Context): Boolean = - ctx.outersIterator.exists{ c => - c.owner == sym.owner - || sym.owner.isClass && c.owner.isClass - && c.owner.thisType.baseClasses.contains(sym.owner) - && c.owner.thisType.member(sym.name).alternatives.contains(sym) - } - - /** Given an import and accessibility, return selector that matches import<->symbol */ - private def isInImport(selData: ImportSelectorData, altName: Option[Name], isDerived: Boolean)(using Context): Boolean = - assert(sym.exists, s"Symbol $sym does not exist") - - val selector = selData.selector - - if !selector.isWildcard then - if altName.exists(explicitName => selector.rename != explicitName.toTermName) then - // if there is an explicit name, it must match - false - else - if isDerived then - // See i15503i.scala, grep for "package foo.test.i17156" - selData.allSymbolsDealiasedForNamed.contains(dealias(sym)) - else - selData.allSymbolsForNamed.contains(sym) - else - // Wildcard - if selData.excludedMembers.contains(altName.getOrElse(sym.name).toTermName) then - // Wildcard with exclusions that match the symbol - false - else if !selData.qualTpe.member(sym.name).hasAltWith(_.symbol == sym) then - // The qualifier does not have the target symbol as a member - false - else - if selector.isGiven then - // Further check that the symbol is a given or implicit and conforms to the bound - sym.isOneOf(Given | Implicit) - && (selector.bound.isEmpty || sym.info.finalResultType <:< selector.boundTpe) - else - // Normal wildcard, check that the symbol is not a given (but can be implicit) - !sym.is(Given) - end if - end isInImport - - /** Annotated with @unused */ - private def isUnusedAnnot(using Context): Boolean = - sym.annotations.exists(a => a.symbol == ctx.definitions.UnusedAnnot) - - private def shouldNotReportParamOwner(using Context): Boolean = - if sym.exists then - val owner = sym.owner - trivialDefs(owner) || // is a trivial def - owner.isPrimaryConstructor || - owner.annotations.exists ( // @depreacated - _.symbol == ctx.definitions.DeprecatedAnnot - ) || - owner.isAllOf(Synthetic | PrivateLocal) || - owner.is(Accessor) || - owner.isOverriden - else - false - - private def usedDefContains(using Context): Boolean = - sym.everySymbol.exists(usedDef.apply) - - private def everySymbol(using Context): List[Symbol] = - List(sym, sym.companionClass, sym.companionModule, sym.moduleClass).filter(_.exists) - - /** A function is overriden. Either has `override flags` or parent has a matching member (type and name) */ - private def isOverriden(using Context): Boolean = - sym.is(Flags.Override) || (sym.exists && sym.owner.thisType.parents.exists(p => sym.matchingMember(p).exists)) - - end extension - - extension (defdef: tpd.DefDef) - // so trivial that it never consumes params - private def isTrivial(using Context): Boolean = - val rhs = defdef.rhs - rhs.symbol == ctx.definitions.Predef_undefined || - rhs.tpe =:= ctx.definitions.NothingType || - defdef.symbol.is(Deferred) || - (rhs match { - case _: tpd.Literal => true - case _ => rhs.tpe match - case ConstantType(_) => true - case tp: TermRef => - // Detect Scala 2 SingleType - tp.underlying.classSymbol.is(Flags.Module) - case _ => - false - }) - def registerTrivial(using Context): Unit = - if defdef.isTrivial then - trivialDefs += defdef.symbol - - extension (memDef: tpd.MemberDef) - private def isValidMemberDef(using Context): Boolean = - memDef.symbol.exists - && !memDef.symbol.isUnusedAnnot - && !memDef.symbol.isAllOf(Flags.AccessorCreationFlags) - && !memDef.name.isWildcard - && !memDef.symbol.owner.is(ExtensionMethod) - - private def isValidParam(using Context): Boolean = - val sym = memDef.symbol - (sym.is(Param) || sym.isAllOf(PrivateParamAccessor | Local, butNot = CaseAccessor)) && - !isSyntheticMainParam(sym) && - !sym.shouldNotReportParamOwner - - private def shouldReportPrivateDef(using Context): Boolean = - currScopeType.top == ScopeType.Template && !memDef.symbol.isConstructor && memDef.symbol.is(Private, butNot = SelfName | Synthetic | CaseAccessor) - - private def isUnsetVarDef(using Context): Boolean = - val sym = memDef.symbol - sym.is(Mutable) && !setVars(sym) - - extension (imp: tpd.Import) - /** Enum generate an import for its cases (but outside them), which should be ignored */ - def isGeneratedByEnum(using Context): Boolean = - imp.symbol.exists && imp.symbol.owner.is(Flags.Enum, butNot = Flags.Case) - - extension (thisName: Name) - private def isWildcard: Boolean = - thisName == StdNames.nme.WILDCARD || thisName.is(WildcardParamName) - - end UnusedData - - private object UnusedData: - enum ScopeType: - case Local - case Template - case ReplWrapper - case Other - - object ScopeType: - /** return the scope corresponding to the enclosing scope of the given tree */ - def fromTree(tree: tpd.Tree)(using Context): ScopeType = tree match - case tree: tpd.Template => if tree.symbol.name.isReplWrapperName then ReplWrapper else Template - case _:tpd.Block => Local - case _ => Other - - final class ImportSelectorData(val qualTpe: Type, val selector: ImportSelector): - private var myUsed: Boolean = false - var excludedMembers: Set[TermName] = Set.empty - - def markUsed(): Unit = myUsed = true - - def isUsed: Boolean = myUsed - - def markExcluded(excluded: Set[TermName]): Unit = excludedMembers ++= excluded - - private var myAllSymbols: Set[Symbol] | Null = null - - def allSymbolsForNamed(using Context): Set[Symbol] = - if myAllSymbols == null then - val allDenots = qualTpe.member(selector.name).alternatives ::: qualTpe.member(selector.name.toTypeName).alternatives - myAllSymbols = allDenots.map(_.symbol).toSet - myAllSymbols.uncheckedNN - - private var myAllSymbolsDealiased: Set[Symbol] | Null = null - - def allSymbolsDealiasedForNamed(using Context): Set[Symbol] = - if myAllSymbolsDealiased == null then - myAllSymbolsDealiased = allSymbolsForNamed.map(sym => dealias(sym)) - myAllSymbolsDealiased.uncheckedNN - end ImportSelectorData - - case class UnusedSymbol(pos: SrcPos, name: Name, warnType: WarnTypes) - /** A container for the results of the used elements analysis */ - case class UnusedResult(warnings: Set[UnusedSymbol]) - object UnusedResult: - val Empty = UnusedResult(Set.empty) - end UnusedData - - private def dealias(symbol: Symbol)(using Context): Symbol = - if symbol.isType && symbol.asType.denot.isAliasType then - symbol.asType.typeRef.dealias.typeSymbol - else - symbol + /** Generated import of cases from enum companion. */ + def isGeneratedByEnum(using Context): Boolean = + imp.symbol.exists && imp.symbol.owner.is(Enum, butNot = Case) + /** Under -Wunused:strict-no-implicit-warn, avoid false positives + * if this selector is a wildcard that might import implicits or + * specifically does import an implicit. + * Similarly, import of CanEqual must not warn, as it is always witness. + */ + def isLoose(sel: ImportSelector)(using Context): Boolean = + if ctx.settings.WunusedHas.strictNoImplicitWarn then + if sel.isWildcard + || imp.expr.tpe.member(sel.name.toTermName).hasAltWith(_.symbol.isOneOf(GivenOrImplicit)) + || imp.expr.tpe.member(sel.name.toTypeName).hasAltWith(_.symbol.isOneOf(GivenOrImplicit)) + then return true + if sel.isWildcard && sel.isGiven + then imp.expr.tpe.allMembers.exists(_.symbol.isCanEqual) + else imp.expr.tpe.member(sel.name.toTermName).hasAltWith(_.symbol.isCanEqual) + + extension (pos: SrcPos) + def isZeroExtentSynthetic: Boolean = pos.span.isSynthetic && pos.span.start == pos.span.end + + extension [A <: AnyRef](arr: Array[A]) + // returns `until` if not satisfied + def indexSatisfying(from: Int, until: Int = arr.length)(p: A => Boolean): Int = + var i = from + while i < until && !p(arr(i)) do + i += 1 + i end CheckUnused diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 72a3ff7324e8..9134e9736079 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -193,7 +193,9 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase ++ sym.annotations) else if sym.is(Param) then - sym.keepAnnotationsCarrying(thisPhase, Set(defn.ParamMetaAnnot), orNoneOf = defn.NonBeanMetaAnnots) + // @unused is getter/setter but we want it on ordinary method params + if !sym.owner.is(Method) || sym.owner.isConstructor then + sym.keepAnnotationsCarrying(thisPhase, Set(defn.ParamMetaAnnot), orNoneOf = defn.NonBeanMetaAnnots) else if sym.is(ParamAccessor) then sym.keepAnnotationsCarrying(thisPhase, Set(defn.GetterMetaAnnot, defn.FieldMetaAnnot)) else diff --git a/compiler/src/dotty/tools/dotc/typer/Deriving.scala b/compiler/src/dotty/tools/dotc/typer/Deriving.scala index cc940ee38e41..febb12cf1007 100644 --- a/compiler/src/dotty/tools/dotc/typer/Deriving.scala +++ b/compiler/src/dotty/tools/dotc/typer/Deriving.scala @@ -10,7 +10,7 @@ import Contexts.*, Symbols.*, Types.*, SymDenotations.*, Names.*, NameOps.*, Fla import ProtoTypes.*, ContextOps.* import util.Spans.* import util.SrcPos -import collection.mutable +import collection.mutable.ListBuffer import ErrorReporting.errorTree /** A typer mixin that implements type class derivation functionality */ @@ -25,8 +25,8 @@ trait Deriving { */ class Deriver(cls: ClassSymbol, codePos: SrcPos)(using Context) { - /** A buffer for synthesized symbols for type class instances */ - private var synthetics = new mutable.ListBuffer[Symbol] + /** A buffer for synthesized symbols for type class instances, with what user asked to synthesize. */ + private val synthetics = ListBuffer.empty[(tpd.Tree, Symbol)] /** A version of Type#underlyingClassRef that works also for higher-kinded types */ private def underlyingClassRef(tp: Type): Type = tp match { @@ -41,7 +41,7 @@ trait Deriving { * an instance with the same name does not exist already. * @param reportErrors Report an error if an instance with the same name exists already */ - private def addDerivedInstance(clsName: Name, info: Type, pos: SrcPos): Unit = { + private def addDerivedInstance(derived: tpd.Tree, clsName: Name, info: Type, pos: SrcPos): Unit = { val instanceName = "derived$".concat(clsName) if (ctx.denotNamed(instanceName).exists) report.error(em"duplicate type class derivation for $clsName", pos) @@ -50,9 +50,8 @@ trait Deriving { // derived instance will have too low a priority to be selected over a freshly // derived instance at the summoning site. val flags = if info.isInstanceOf[MethodOrPoly] then GivenMethod else Given | Lazy - synthetics += - newSymbol(ctx.owner, instanceName, flags, info, coord = pos.span) - .entered + val sym = newSymbol(ctx.owner, instanceName, flags, info, coord = pos.span).entered + synthetics += derived -> sym } /** Check derived type tree `derived` for the following well-formedness conditions: @@ -77,7 +76,8 @@ trait Deriving { * that have the same name but different prefixes through selective aliasing. */ private def processDerivedInstance(derived: untpd.Tree): Unit = { - val originalTypeClassType = typedAheadType(derived, AnyTypeConstructorProto).tpe + val originalTypeClassTree = typedAheadType(derived, AnyTypeConstructorProto) + val originalTypeClassType = originalTypeClassTree.tpe val underlyingClassType = underlyingClassRef(originalTypeClassType) val typeClassType = checkClassType( underlyingClassType.orElse(originalTypeClassType), @@ -100,7 +100,7 @@ trait Deriving { val derivedInfo = if derivedParams.isEmpty then monoInfo else PolyType.fromParams(derivedParams, monoInfo) - addDerivedInstance(originalTypeClassType.typeSymbol.name, derivedInfo, derived.srcPos) + addDerivedInstance(originalTypeClassTree, originalTypeClassType.typeSymbol.name, derivedInfo, derived.srcPos) } def deriveSingleParameter: Unit = { @@ -312,7 +312,7 @@ trait Deriving { else tpd.ValDef(sym.asTerm, typeclassInstance(sym)(Nil)) } - synthetics.map(syntheticDef).toList + synthetics.map((t, s) => syntheticDef(s).withAttachment(Deriving.OriginalTypeClass, t)).toList } def finalize(stat: tpd.TypeDef): tpd.Tree = { @@ -321,3 +321,8 @@ trait Deriving { } } } +object Deriving: + import dotty.tools.dotc.util.Property + + /** Attachment holding the name of a type class as written by the user. */ + val OriginalTypeClass = Property.StickyKey[tpd.Tree] diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index d46c85b38e9d..38bc6960e370 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -77,6 +77,9 @@ object Typer { /** Indicates that an expression is explicitly ascribed to [[Unit]] type. */ val AscribedToUnit = new Property.StickyKey[Unit] + /** Tree adaptation lost fidelity; this attachment preserves the original tree. */ + val AdaptedTree = new Property.StickyKey[tpd.Tree] + /** An attachment on a Select node with an `apply` field indicating that the `apply` * was inserted by the Typer. */ @@ -3057,7 +3060,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer def typedTuple(tree: untpd.Tuple, pt: Type)(using Context): Tree = { val arity = tree.trees.length if (arity <= Definitions.MaxTupleArity) - typed(desugar.smallTuple(tree).withSpan(tree.span), pt) + typed(desugar.smallTuple(tree).withSpan(tree.span).withAttachmentsFrom(tree), pt) else { val pts = pt.tupleElementTypes match @@ -4204,12 +4207,12 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer /** Adapt an expression of constant type to a different constant type `tpe`. */ def adaptConstant(tree: Tree, tpe: ConstantType): Tree = { - def lit = Literal(tpe.value).withSpan(tree.span) + def lit = Literal(tpe.value).withSpan(tree.span).withAttachment(AdaptedTree, tree) tree match { case Literal(c) => lit case tree @ Block(stats, expr) => tpd.cpy.Block(tree)(stats, adaptConstant(expr, tpe)) case tree => - if (isIdempotentExpr(tree)) lit // See discussion in phase Literalize why we demand isIdempotentExpr + if isIdempotentExpr(tree) then lit // See discussion in phase FirstTransform why we demand isIdempotentExpr else Block(tree :: Nil, lit) } } diff --git a/compiler/src/dotty/tools/dotc/util/chaining.scala b/compiler/src/dotty/tools/dotc/util/chaining.scala new file mode 100644 index 000000000000..0c61ab6e73e9 --- /dev/null +++ b/compiler/src/dotty/tools/dotc/util/chaining.scala @@ -0,0 +1,8 @@ + +package dotty.tools.dotc.util + +object chaining: + + extension [A](x: A) + inline def tap(inline f: A => Unit): x.type = { f(x): Unit; x } + inline def pipe[B](inline f: A => B): B = f(x) diff --git a/compiler/src/dotty/tools/repl/ReplCompiler.scala b/compiler/src/dotty/tools/repl/ReplCompiler.scala index 5c8dcc2616b7..06c81c499e5d 100644 --- a/compiler/src/dotty/tools/repl/ReplCompiler.scala +++ b/compiler/src/dotty/tools/repl/ReplCompiler.scala @@ -11,7 +11,7 @@ import dotty.tools.dotc.core.Phases.Phase import dotty.tools.dotc.core.StdNames.* import dotty.tools.dotc.core.Symbols.* import dotty.tools.dotc.reporting.Diagnostic -import dotty.tools.dotc.transform.PostTyper +import dotty.tools.dotc.transform.{CheckUnused, CheckShadowing, PostTyper} import dotty.tools.dotc.typer.ImportInfo.{withRootImports, RootRef} import dotty.tools.dotc.typer.TyperPhase import dotty.tools.dotc.util.Spans.* @@ -36,6 +36,7 @@ class ReplCompiler extends Compiler: List(Parser()), List(ReplPhase()), List(TyperPhase(addRootImports = false)), + List(CheckUnused.PostTyper(), CheckShadowing()), List(CollectTopLevelImports()), List(PostTyper()), ) diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index 71bf5a7e7844..1b33c52416ea 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -69,6 +69,7 @@ class CompilationTests { compileFile("tests/rewrites/i17399.scala", unindentOptions.and("-rewrite")), compileFile("tests/rewrites/i20002.scala", defaultOptions.and("-indent", "-rewrite")), compileFile("tests/rewrites/i21382.scala", defaultOptions.and("-indent", "-rewrite")), + compileFile("tests/rewrites/unused.scala", defaultOptions.and("-rewrite", "-Wunused:all")), ).checkRewrites() } diff --git a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala index 7d32b3d6c9fa..e15103046fbf 100644 --- a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala +++ b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala @@ -746,13 +746,14 @@ trait ParallelTesting extends RunnerOrchestration { self => diffCheckfile(testSource, reporters, logger) override def maybeFailureMessage(testSource: TestSource, reporters: Seq[TestReporter]): Option[String] = - lazy val (map, expCount) = getWarnMapAndExpectedCount(testSource.sourceFiles.toIndexedSeq) + lazy val (expected, expCount) = getWarnMapAndExpectedCount(testSource.sourceFiles.toIndexedSeq) lazy val obtCount = reporters.foldLeft(0)(_ + _.warningCount) - lazy val (expected, unexpected) = getMissingExpectedWarnings(map, reporters.iterator.flatMap(_.diagnostics)) - lazy val diagnostics = reporters.flatMap(_.diagnostics.toSeq.sortBy(_.pos.line).map(e => s" at ${e.pos.line + 1}: ${e.message}")) - def showLines(title: String, lines: Seq[String]) = if lines.isEmpty then "" else title + lines.mkString("\n", "\n", "") - def hasMissingAnnotations = expected.nonEmpty || unexpected.nonEmpty - def showDiagnostics = showLines("-> following the diagnostics:", diagnostics) + lazy val (unfulfilled, unexpected) = getMissingExpectedWarnings(expected, diagnostics.iterator) + lazy val diagnostics = reporters.flatMap(_.diagnostics.toSeq.sortBy(_.pos.line)) + lazy val messages = diagnostics.map(d => s" at ${d.pos.line + 1}: ${d.message}") + def showLines(title: String, lines: Seq[String]) = if lines.isEmpty then "" else lines.mkString(s"$title\n", "\n", "") + def hasMissingAnnotations = unfulfilled.nonEmpty || unexpected.nonEmpty + def showDiagnostics = showLines("-> following the diagnostics:", messages) Option: if reporters.exists(_.errorCount > 0) then s"""Compilation failed for: ${testSource.title} @@ -761,58 +762,63 @@ trait ParallelTesting extends RunnerOrchestration { self => else if expCount != obtCount then s"""|Wrong number of warnings encountered when compiling $testSource |expected: $expCount, actual: $obtCount - |${showLines("Unfulfilled expectations:", expected)} + |${showLines("Unfulfilled expectations:", unfulfilled)} |${showLines("Unexpected warnings:", unexpected)} |$showDiagnostics |""".stripMargin.trim.linesIterator.mkString("\n", "\n", "") - else if hasMissingAnnotations then s"\nWarnings found on incorrect row numbers when compiling $testSource\n$showDiagnostics" - else if !map.isEmpty then s"\nExpected warnings(s) have {=}: $map" + else if hasMissingAnnotations then + s"""|Warnings found on incorrect row numbers when compiling $testSource + |${showLines("Unfulfilled expectations:", unfulfilled)} + |${showLines("Unexpected warnings:", unexpected)} + |$showDiagnostics + |""".stripMargin.trim.linesIterator.mkString("\n", "\n", "") + else if !expected.isEmpty then s"\nExpected warnings(s) have {=}: $expected" else null end maybeFailureMessage def getWarnMapAndExpectedCount(files: Seq[JFile]): (HashMap[String, Integer], Int) = - val comment = raw"//( *)(nopos-)?warn".r - val map = new HashMap[String, Integer]() + val comment = raw"//(?: *)(nopos-)?warn".r + val map = HashMap[String, Integer]() var count = 0 def bump(key: String): Unit = map.get(key) match case null => map.put(key, 1) case n => map.put(key, n+1) count += 1 - files.filter(isSourceFile).foreach { file => - Using(Source.fromFile(file, StandardCharsets.UTF_8.name)) { source => - source.getLines.zipWithIndex.foreach { case (line, lineNbr) => - comment.findAllMatchIn(line).foreach { m => - m.group(2) match - case "nopos-" => - bump("nopos") - case _ => bump(s"${file.getPath}:${lineNbr+1}") - } - } - }.get - } + for file <- files if isSourceFile(file) do + Using.resource(Source.fromFile(file, StandardCharsets.UTF_8.name)) { source => + source.getLines.zipWithIndex.foreach: (line, lineNbr) => + comment.findAllMatchIn(line).foreach: + case comment("nopos-") => bump("nopos") + case _ => bump(s"${file.getPath}:${lineNbr+1}") + } + end for (map, count) - def getMissingExpectedWarnings(map: HashMap[String, Integer], reporterWarnings: Iterator[Diagnostic]): (List[String], List[String]) = - val unexpected, unpositioned = ListBuffer.empty[String] + // return unfulfilled expected warnings and unexpected diagnostics + def getMissingExpectedWarnings(expected: HashMap[String, Integer], reporterWarnings: Iterator[Diagnostic]): (List[String], List[String]) = + val unexpected = ListBuffer.empty[String] def relativize(path: String): String = path.split(JFile.separatorChar).dropWhile(_ != "tests").mkString(JFile.separator) def seenAt(key: String): Boolean = - map.get(key) match + expected.get(key) match case null => false - case 1 => map.remove(key) ; true - case n => map.put(key, n - 1) ; true + case 1 => expected.remove(key); true + case n => expected.put(key, n - 1); true def sawDiagnostic(d: Diagnostic): Unit = val srcpos = d.pos.nonInlined if srcpos.exists then val key = s"${relativize(srcpos.source.file.toString())}:${srcpos.line + 1}" if !seenAt(key) then unexpected += key else - if(!seenAt("nopos")) unpositioned += relativize(srcpos.source.file.toString()) + if !seenAt("nopos") then unexpected += relativize(srcpos.source.file.toString) reporterWarnings.foreach(sawDiagnostic) - (map.asScala.keys.toList, (unexpected ++ unpositioned).toList) + val splitter = raw"(?:[^:]*):(\d+)".r + val unfulfilled = expected.asScala.keys.toList.sortBy { case splitter(n) => n.toInt case _ => -1 } + (unfulfilled, unexpected.toList) end getMissingExpectedWarnings + end WarnTest private final class RewriteTest(testSources: List[TestSource], checkFiles: Map[JFile, JFile], times: Int, threadLimit: Option[Int], suppressAllOutput: Boolean)(implicit summaryReport: SummaryReporting) extends Test(testSources, times, threadLimit, suppressAllOutput) { @@ -947,8 +953,8 @@ trait ParallelTesting extends RunnerOrchestration { self => def seenAt(key: String): Boolean = errorMap.get(key) match case null => false - case 1 => errorMap.remove(key) ; true - case n => errorMap.put(key, n - 1) ; true + case 1 => errorMap.remove(key); true + case n => errorMap.put(key, n - 1); true def sawDiagnostic(d: Diagnostic): Unit = d.pos.nonInlined match case srcpos if srcpos.exists => diff --git a/library/src/scala/deriving/Mirror.scala b/library/src/scala/deriving/Mirror.scala index 57453a516567..a7477cf0fb2d 100644 --- a/library/src/scala/deriving/Mirror.scala +++ b/library/src/scala/deriving/Mirror.scala @@ -52,7 +52,7 @@ object Mirror { extension [T](p: ProductOf[T]) /** Create a new instance of type `T` with elements taken from product `a`. */ - def fromProductTyped[A <: scala.Product, Elems <: p.MirroredElemTypes](a: A)(using m: ProductOf[A] { type MirroredElemTypes = Elems }): T = + def fromProductTyped[A <: scala.Product, Elems <: p.MirroredElemTypes](a: A)(using ProductOf[A] { type MirroredElemTypes = Elems }): T = p.fromProduct(a) /** Create a new instance of type `T` with elements taken from tuple `t`. */ diff --git a/library/src/scala/quoted/Quotes.scala b/library/src/scala/quoted/Quotes.scala index 873d5e1e993e..c5d0022b6cf5 100644 --- a/library/src/scala/quoted/Quotes.scala +++ b/library/src/scala/quoted/Quotes.scala @@ -1,7 +1,6 @@ package scala.quoted -import scala.annotation.experimental -import scala.annotation.implicitNotFound +import scala.annotation.{experimental, implicitNotFound, unused} import scala.reflect.TypeTest /** Current Quotes in scope @@ -4797,7 +4796,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => foldTree(foldTree(foldTree(x, cond)(owner), thenp)(owner), elsep)(owner) case While(cond, body) => foldTree(foldTree(x, cond)(owner), body)(owner) - case Closure(meth, tpt) => + case Closure(meth, _) => foldTree(x, meth)(owner) case Match(selector, cases) => foldTrees(foldTree(x, selector)(owner), cases)(owner) @@ -4875,7 +4874,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => def traverseTree(tree: Tree)(owner: Symbol): Unit = traverseTreeChildren(tree)(owner) - def foldTree(x: Unit, tree: Tree)(owner: Symbol): Unit = traverseTree(tree)(owner) + def foldTree(@unused x: Unit, tree: Tree)(owner: Symbol): Unit = traverseTree(tree)(owner) protected def traverseTreeChildren(tree: Tree)(owner: Symbol): Unit = foldOverTree((), tree)(owner) diff --git a/library/src/scala/runtime/Arrays.scala b/library/src/scala/runtime/Arrays.scala index 2d98caea4df8..97ff589c6610 100644 --- a/library/src/scala/runtime/Arrays.scala +++ b/library/src/scala/runtime/Arrays.scala @@ -1,5 +1,6 @@ package scala.runtime +import scala.annotation.unused import scala.reflect.ClassTag import java.lang.{reflect => jlr} @@ -26,6 +27,6 @@ object Arrays { /** Create an array of a reference type T. */ - def newArray[Arr](componentType: Class[_], returnType: Class[Arr], dimensions: Array[Int]): Arr = + def newArray[Arr](componentType: Class[_], @unused returnType: Class[Arr], dimensions: Array[Int]): Arr = jlr.Array.newInstance(componentType, dimensions: _*).asInstanceOf[Arr] } diff --git a/project/Build.scala b/project/Build.scala index bce4ad9819eb..82d9cb786811 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -240,7 +240,9 @@ object Build { "-deprecation", "-unchecked", //"-Wconf:cat=deprecation&msg=Unsafe:s", // example usage - "-Xfatal-warnings", // -Werror in modern usage + "-Werror", + //"-Wunused:all", + //"-rewrite", // requires -Werror:false since no rewrites are applied with errors "-encoding", "UTF8", "-language:implicitConversions", ), @@ -1068,7 +1070,7 @@ object Build { ) }, Compile / doc / scalacOptions += "-Ydocument-synthetic-types", - scalacOptions -= "-Xfatal-warnings", + scalacOptions += "-Werror:false", ivyConfigurations += SourceDeps.hide, transitiveClassifiers := Seq("sources"), libraryDependencies += @@ -1351,7 +1353,7 @@ object Build { dependsOn(`scala3-library-bootstrappedJS`). settings( bspEnabled := false, - scalacOptions --= Seq("-Xfatal-warnings", "-deprecation"), + scalacOptions --= Seq("-Werror", "-deprecation"), // Required to run Scala.js tests. Test / fork := false, diff --git a/tasty/src/dotty/tools/tasty/TastyReader.scala b/tasty/src/dotty/tools/tasty/TastyReader.scala index 31407f7a4ab8..18e94867e26e 100644 --- a/tasty/src/dotty/tools/tasty/TastyReader.scala +++ b/tasty/src/dotty/tools/tasty/TastyReader.scala @@ -99,7 +99,7 @@ class TastyReader(val bytes: Array[Byte], start: Int, end: Int, val base: Int = /** Read an uncompressed Long stored in 8 bytes in big endian format */ def readUncompressedLong(): Long = { var x: Long = 0 - for (i <- 0 to 7) + for (_ <- 0 to 7) x = (x << 8) | (readByte() & 0xff) x } diff --git a/tests/pos/i11729.scala b/tests/pos/i11729.scala index e97b285ac6a2..79d3174dc2e9 100644 --- a/tests/pos/i11729.scala +++ b/tests/pos/i11729.scala @@ -6,7 +6,7 @@ type Return[X] = X match object Return: def apply[A](a:A):Return[A] = a match - case a: List[t] => a + case a: List[?] => a case a: Any => List(a) object Test1: @@ -18,7 +18,7 @@ type Boxed[X] = X match case Any => Box[X] def box[X](x: X): Boxed[X] = x match - case b: Box[t] => b + case b: Box[?] => b case x: Any => Box(x) case class Box[A](a:A): diff --git a/tests/pos/i17631.scala b/tests/pos/i17631.scala index 7b8a064493df..ddcb71354968 100644 --- a/tests/pos/i17631.scala +++ b/tests/pos/i17631.scala @@ -1,4 +1,4 @@ -//> using options -Xfatal-warnings -Wunused:all -deprecation -feature +//> using options -Werror -Wunused:all -deprecation -feature object foo { type Bar @@ -32,3 +32,23 @@ object Main { (bad1, bad2) } } + +def `i18388`: Unit = + def func(pred: [A] => A => Boolean): Unit = + val _ = pred + () + val _ = func + +trait L[T]: + type E + +def `i19748` = + type Warn1 = [T] => (l: L[T]) => T => l.E + type Warn2 = [T] => L[T] => T + type Warn3 = [T] => T => T + def use(x: (Warn1, Warn2, Warn3)) = x + use + +type NoWarning1 = [T] => (l: L[T]) => T => l.E +type NoWarning2 = [T] => L[T] => T +type NoWarning3 = [T] => T => T diff --git a/tests/pos/i18366.scala b/tests/pos/i18366.scala deleted file mode 100644 index 698510ad13a2..000000000000 --- a/tests/pos/i18366.scala +++ /dev/null @@ -1,10 +0,0 @@ -//> using options -Xfatal-warnings -Wunused:all - -trait Builder { - def foo(): Unit -} - -def repro = - val builder: Builder = ??? - import builder.{foo => bar} - bar() \ No newline at end of file diff --git a/tests/pos/i3323.scala b/tests/pos/i3323.scala deleted file mode 100644 index 94d072d4a2fc..000000000000 --- a/tests/pos/i3323.scala +++ /dev/null @@ -1,9 +0,0 @@ -//> using options -Xfatal-warnings -deprecation -feature - -class Foo { - def foo[A](lss: List[List[A]]): Unit = { - lss match { - case xss: List[List[A]] => - } - } -} diff --git a/tests/pos/tuple-exaustivity.scala b/tests/pos/tuple-exaustivity.scala deleted file mode 100644 index a27267fc89e5..000000000000 --- a/tests/pos/tuple-exaustivity.scala +++ /dev/null @@ -1,6 +0,0 @@ -//> using options -Xfatal-warnings -deprecation -feature - -def test(t: Tuple) = - t match - case Tuple() => - case head *: tail => diff --git a/tests/rewrites/ambiguous-named-tuple-assignment.check b/tests/rewrites/ambiguous-named-tuple-assignment.check new file mode 100644 index 000000000000..00e6cc4112f1 --- /dev/null +++ b/tests/rewrites/ambiguous-named-tuple-assignment.check @@ -0,0 +1,19 @@ +import scala.language.experimental.namedTuples + +object i21770: + def f(g: Int => Unit) = g(0) + var cache: Option[Int] = None + f(i => {cache = Some(i)}) + +object i21861: + var age: Int = 28 + { + age = 29 + } + + +object i21861c: + def age: Int = ??? + def age_=(x: Int): Unit = () + age = 29 + { age = 29 } diff --git a/tests/rewrites/ambiguous-named-tuple-assignment.scala b/tests/rewrites/ambiguous-named-tuple-assignment.scala new file mode 100644 index 000000000000..e9685b7b58cf --- /dev/null +++ b/tests/rewrites/ambiguous-named-tuple-assignment.scala @@ -0,0 +1,19 @@ +import scala.language.experimental.namedTuples + +object i21770: + def f(g: Int => Unit) = g(0) + var cache: Option[Int] = None + f(i => (cache = Some(i))) + +object i21861: + var age: Int = 28 + ( + age = 29 + ) + + +object i21861c: + def age: Int = ??? + def age_=(x: Int): Unit = () + age = 29 + ( age = 29 ) diff --git a/tests/rewrites/unused.check b/tests/rewrites/unused.check new file mode 100644 index 000000000000..1ff93bfb6ef2 --- /dev/null +++ b/tests/rewrites/unused.check @@ -0,0 +1,55 @@ + +//> using options -Wunused:all + +package p1: + import java.lang.Runnable + class C extends Runnable { def run() = () } + +package p2: + import java.lang.Runnable + class C extends Runnable { def run() = () } + +package p3: + import java.lang.Runnable + class C extends Runnable { def run() = () } + +package p4: + import java.lang.{Runnable, System}, System.out + class C extends Runnable { def run() = out.println() } + +package p5: + import java.lang.{Runnable, System}, System.out + class C extends Runnable { def run() = out.println() } + +package p6: + import java.lang.{Runnable, System}, System.out + class C extends Runnable { def run() = out.println() } + +package p7: + import java.lang.{Runnable, + System}, System.out + class C extends Runnable { def run() = out.println() } + +package p8: + import java.lang.{Runnable as R, System}, System.out + class C extends R { def run() = out.println() } + +package p9: + import java.lang.{Runnable as R, System, + Thread} + class C extends R { def run() = Thread(() => System.out.println()).start() } + +package p10: + object X: + def x = 42 + class C: + import X.* // preserve text, don't rewrite to p10.X.* + def c = x + +package p11: + import collection.mutable, mutable.ListBuffer // warn // warn // not checked :( + def buf = ListBuffer.empty[String] + +package p12: + import java.lang.System, java.lang.Runnable + class C extends Runnable { def run() = System.out.println() } diff --git a/tests/rewrites/unused.scala b/tests/rewrites/unused.scala new file mode 100644 index 000000000000..85a83c7c0015 --- /dev/null +++ b/tests/rewrites/unused.scala @@ -0,0 +1,61 @@ + +//> using options -Wunused:all + +package p1: + import java.lang.Runnable + import java.lang.{Thread, String}, java.lang.Integer + class C extends Runnable { def run() = () } + +package p2: + import java.lang.Thread + import java.lang.String + import java.lang.Runnable + import java.lang.Integer + class C extends Runnable { def run() = () } + +package p3: + import java.lang.{Runnable, Thread, String} + class C extends Runnable { def run() = () } + +package p4: + import java.lang.{Runnable, System, Thread}, System.out + class C extends Runnable { def run() = out.println() } + +package p5: + import java.lang.{Thread, Runnable, System}, System.out + class C extends Runnable { def run() = out.println() } + +package p6: + import java.lang.{Runnable, System}, java.lang.Thread, System.out + class C extends Runnable { def run() = out.println() } + +package p7: + import java.lang.{Runnable, + Thread, + System}, System.out + class C extends Runnable { def run() = out.println() } + +package p8: + import java.lang.{Runnable as R, System, + Thread}, System.out + class C extends R { def run() = out.println() } + +package p9: + import java.lang.{Runnable as R, System, + Thread}, System.out + class C extends R { def run() = Thread(() => System.out.println()).start() } + +package p10: + object X: + def x = 42 + class C: + import X.*, java.util.HashMap // preserve text, don't rewrite to p10.X.* + def c = x + +package p11: + import collection.mutable, mutable.ListBuffer, java.lang.{Runnable, Thread} // warn // warn // not checked :( + def buf = ListBuffer.empty[String] + +package p12: + import collection.mutable, java.lang.System, java.lang.Runnable + class C extends Runnable { def run() = System.out.println() } diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index 7153edac00ab..31a08dbb9e60 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -61,23 +61,23 @@ Synthetics => 3 entries Symbols: advanced/C# => class C [typeparam T ] extends Object { self: C[T] => +3 decls } -advanced/C#[T] => typeparam T +advanced/C#[T] => typeparam T advanced/C#``(). => primary ctor [typeparam T ](): C[T] advanced/C#t(). => method t => T advanced/HKClass# => class HKClass [typeparam F [typeparam T ] <: [U] =>> Tuple2[U, T]] extends Object { self: HKClass[F] => +3 decls } advanced/HKClass#[F] => typeparam F [typeparam T ] <: [U] =>> Tuple2[U, T] -advanced/HKClass#[F][T] => typeparam T -advanced/HKClass#[F][U] => typeparam U +advanced/HKClass#[F][T] => typeparam T +advanced/HKClass#[F][U] => typeparam U advanced/HKClass#``(). => primary ctor [typeparam F [typeparam T ] <: [U] =>> Tuple2[U, T]](): HKClass[F] -advanced/HKClass#``().[F][T] => typeparam T -advanced/HKClass#``().[F][U] => typeparam U +advanced/HKClass#``().[F][T] => typeparam T +advanced/HKClass#``().[F][U] => typeparam U advanced/HKClass#foo(). => method foo [typeparam T , typeparam U ](param x: F[T, U]): String advanced/HKClass#foo().(x) => param x: F[T, U] -advanced/HKClass#foo().[T] => typeparam T -advanced/HKClass#foo().[U] => typeparam U +advanced/HKClass#foo().[T] => typeparam T +advanced/HKClass#foo().[U] => typeparam U advanced/Structural# => class Structural extends Object { self: Structural => +6 decls } advanced/Structural#T# => trait T [typeparam A ] extends Object { self: T[A] => +4 decls } -advanced/Structural#T#[A] => typeparam A +advanced/Structural#T#[A] => typeparam A advanced/Structural#T#``(). => primary ctor [typeparam A ](): T[A] advanced/Structural#T#bar(). => method bar (param b: foo.B): Unit advanced/Structural#T#bar().(b) => param b: foo.B @@ -291,8 +291,8 @@ Symbols: annot/Alias. => final object Alias extends Object { self: Alias.type => +2 decls } annot/Alias.A# => type A = ClassAnnotation @param annot/Annotations# => @ClassAnnotation class Annotations [@TypeParameterAnnotation typeparam T ] extends Object { self: AnyRef & Annotations[T] => +6 decls } -annot/Annotations#S# => @TypeAnnotation type S -annot/Annotations#[T] => @TypeParameterAnnotation typeparam T +annot/Annotations#S# => @TypeAnnotation type S +annot/Annotations#[T] => @TypeParameterAnnotation typeparam T annot/Annotations#``(). => primary ctor [@TypeParameterAnnotation typeparam T ](@ParameterAnnotation param x: T): Annotations[T] annot/Annotations#``().(x) => @ParameterAnnotation param x: T annot/Annotations#field. => @FieldAnnotation val method field Int @@ -306,7 +306,7 @@ annot/B#throwing(). => @throws[Exception] method throwing => Nothing annot/B#x. => private[this] val method x Int annot/M. => @ObjectAnnotation final object M extends Object { self: M.type => +1 decls } annot/M.m(). => @MacroAnnotation macro m [typeparam TT ]: Int -annot/M.m().[TT] => typeparam TT +annot/M.m().[TT] => typeparam TT annot/T# => @TraitAnnotation trait T extends Object { self: T => +1 decls } annot/T#``(). => primary ctor (): T local0 => selfparam self: AnyRef @@ -399,10 +399,10 @@ example/Anonymous#bar2. => val method bar2 Bar example/Anonymous#foo. => val method foo Foo example/Anonymous#locally(). => method locally [typeparam A ](param x: A): A example/Anonymous#locally().(x) => param x: A -example/Anonymous#locally().[A] => typeparam A +example/Anonymous#locally().[A] => typeparam A example/Anonymous#m1(). => method m1 [typeparam T [type _ ]]: Nothing example/Anonymous#m1().[T] => typeparam T [type _ ] -example/Anonymous#m1().[T][_] => type _ +example/Anonymous#m1().[T][_] => type _ example/Anonymous#m2(). => method m2 => Map[_, List[_] forSome { type _ }] forSome { type _ } local0 => val local x: Function1[Int, Int] local1 => final class $anon extends Object with Foo { self: $anon => +1 decls } @@ -637,7 +637,7 @@ classes/C11#foo(). => inline macro foo => Int classes/C12# => class C12 extends Object { self: C12 => +8 decls } classes/C12#Context# => class Context extends Object { self: Context => +2 decls } classes/C12#Context#Expr# => type Expr [typeparam T ] -classes/C12#Context#Expr#[T] => typeparam T +classes/C12#Context#Expr#[T] => typeparam T classes/C12#Context#``(). => primary ctor (): Context classes/C12#``(). => primary ctor (): C12 classes/C12#foo1(). => macro foo1 (param x: Int): Int @@ -802,10 +802,15 @@ Occurrences: [53:10..53:11): + -> scala/Int#`+`(+4). Diagnostics: +[13:20..13:21): [warning] unused explicit parameter [18:9..18:10): [warning] unused explicit parameter [20:27..20:28): [warning] unused explicit parameter [22:27..22:28): [warning] unused explicit parameter [24:10..24:11): [warning] unused explicit parameter +[36:11..36:12): [warning] unused explicit parameter +[39:11..39:12): [warning] unused explicit parameter +[39:19..39:20): [warning] unused explicit parameter +[51:30..51:31): [warning] unused explicit parameter Synthetics: [51:16..51:27):List(1).map => *[Int] @@ -923,7 +928,7 @@ endmarkers/MultiCtor#``().(i) => val param i: Int endmarkers/MultiCtor#``(+1). => ctor (): MultiCtor endmarkers/MultiCtor#i. => val method i Int endmarkers/Stuff# => trait Stuff [typeparam A ] extends Object { self: Stuff[A] => +3 decls } -endmarkers/Stuff#[A] => typeparam A +endmarkers/Stuff#[A] => typeparam A endmarkers/Stuff#``(). => primary ctor [typeparam A ](): Stuff[A] endmarkers/Stuff#do(). => abstract method do => A endmarkers/TestObj. => final object TestObj extends Object { self: TestObj.type => +2 decls } @@ -1122,29 +1127,29 @@ _empty_/Enums.Directions.valueOf(). => method valueOf (param $name: String): Dir _empty_/Enums.Directions.valueOf().($name) => param $name: String _empty_/Enums.Directions.values(). => method values => Array[Directions] _empty_/Enums.Maybe# => abstract sealed enum class Maybe [covariant typeparam A ] extends Object with Enum { self: Maybe[A] => +2 decls } -_empty_/Enums.Maybe#[A] => covariant typeparam A +_empty_/Enums.Maybe#[A] => covariant typeparam A _empty_/Enums.Maybe#``(). => primary ctor [covariant typeparam A ](): Maybe[A] _empty_/Enums.Maybe. => final object Maybe extends Object { self: Maybe.type => +6 decls } _empty_/Enums.Maybe.Just# => final case enum class Just [covariant typeparam A ] extends Maybe[A] { self: Just[A] => +7 decls } -_empty_/Enums.Maybe.Just#[A] => covariant typeparam A +_empty_/Enums.Maybe.Just#[A] => covariant typeparam A _empty_/Enums.Maybe.Just#_1(). => method _1 => A _empty_/Enums.Maybe.Just#``(). => primary ctor [covariant typeparam A ](val param value: A): Just[A] _empty_/Enums.Maybe.Just#``().(value) => val param value: A _empty_/Enums.Maybe.Just#copy$default$1(). => method copy$default$1 [covariant typeparam A ]: A -_empty_/Enums.Maybe.Just#copy$default$1().[A] => typeparam A +_empty_/Enums.Maybe.Just#copy$default$1().[A] => typeparam A _empty_/Enums.Maybe.Just#copy(). => method copy [covariant typeparam A ](param value: A): Just[A] _empty_/Enums.Maybe.Just#copy().(value) => param value: A -_empty_/Enums.Maybe.Just#copy().[A] => typeparam A +_empty_/Enums.Maybe.Just#copy().[A] => typeparam A _empty_/Enums.Maybe.Just#ordinal(). => method ordinal => Int <: scala/reflect/Enum#ordinal(). _empty_/Enums.Maybe.Just#value. => val method value A _empty_/Enums.Maybe.Just. => final object Just extends Object { self: Just.type => +4 decls } _empty_/Enums.Maybe.Just.apply(). => method apply [typeparam A ](param value: A): Just[A] _empty_/Enums.Maybe.Just.apply().(value) => param value: A -_empty_/Enums.Maybe.Just.apply().[A] => typeparam A +_empty_/Enums.Maybe.Just.apply().[A] => typeparam A _empty_/Enums.Maybe.Just.toString(). => method toString => String <: scala/Any#toString(). _empty_/Enums.Maybe.Just.unapply(). => method unapply [typeparam A ](param x$1: Just[A]): Just[A] _empty_/Enums.Maybe.Just.unapply().(x$1) => param x$1: Just[A] -_empty_/Enums.Maybe.Just.unapply().[A] => typeparam A +_empty_/Enums.Maybe.Just.unapply().[A] => typeparam A _empty_/Enums.Maybe.None. => case val static enum method None Maybe[Nothing] _empty_/Enums.Maybe.fromOrdinal(). => method fromOrdinal (param ordinal: Int): Maybe[_] forSome { type _ } _empty_/Enums.Maybe.fromOrdinal().(ordinal) => param ordinal: Int @@ -1195,7 +1200,7 @@ _empty_/Enums.Suits.valueOf(). => method valueOf (param $name: String): Suits _empty_/Enums.Suits.valueOf().($name) => param $name: String _empty_/Enums.Suits.values(). => method values => Array[Suits] _empty_/Enums.Tag# => abstract sealed enum class Tag [typeparam A ] extends Object with Enum { self: Tag[A] => +2 decls } -_empty_/Enums.Tag#[A] => typeparam A +_empty_/Enums.Tag#[A] => typeparam A _empty_/Enums.Tag#``(). => primary ctor [typeparam A ](): Tag[A] _empty_/Enums.Tag. => final object Tag extends Object { self: Tag.type => +7 decls } _empty_/Enums.Tag.$values. => private[this] val method $values Array[Tag[_] forSome { type _ }] @@ -1226,33 +1231,33 @@ _empty_/Enums.WeekDays.valueOf(). => method valueOf (param $name: String): WeekD _empty_/Enums.WeekDays.valueOf().($name) => param $name: String _empty_/Enums.WeekDays.values(). => method values => Array[WeekDays] _empty_/Enums.`<:<`# => abstract sealed enum class <:< [contravariant typeparam A , typeparam B ] extends Object with Enum { self: <:<[A, B] => +3 decls } -_empty_/Enums.`<:<`#[A] => contravariant typeparam A -_empty_/Enums.`<:<`#[B] => typeparam B +_empty_/Enums.`<:<`#[A] => contravariant typeparam A +_empty_/Enums.`<:<`#[B] => typeparam B _empty_/Enums.`<:<`#``(). => primary ctor [contravariant typeparam A , typeparam B ](): <:<[A, B] _empty_/Enums.`<:<`. => final object <:< extends Object { self: <:<.type => +6 decls } _empty_/Enums.`<:<`.Refl# => final case enum class Refl [typeparam C ] extends <:<[C, C] { self: Refl[C] => +4 decls } -_empty_/Enums.`<:<`.Refl#[C] => typeparam C +_empty_/Enums.`<:<`.Refl#[C] => typeparam C _empty_/Enums.`<:<`.Refl#``(). => primary ctor [typeparam C ](): Refl[C] _empty_/Enums.`<:<`.Refl#copy(). => method copy [typeparam C ](): Refl[C] -_empty_/Enums.`<:<`.Refl#copy().[C] => typeparam C +_empty_/Enums.`<:<`.Refl#copy().[C] => typeparam C _empty_/Enums.`<:<`.Refl#ordinal(). => method ordinal => Int <: scala/reflect/Enum#ordinal(). _empty_/Enums.`<:<`.Refl. => final object Refl extends Object { self: Refl.type => +4 decls } _empty_/Enums.`<:<`.Refl.apply(). => method apply [typeparam C ](): Refl[C] -_empty_/Enums.`<:<`.Refl.apply().[C] => typeparam C +_empty_/Enums.`<:<`.Refl.apply().[C] => typeparam C _empty_/Enums.`<:<`.Refl.toString(). => method toString => String <: scala/Any#toString(). _empty_/Enums.`<:<`.Refl.unapply(). => method unapply [typeparam C ](param x$1: Refl[C]): true _empty_/Enums.`<:<`.Refl.unapply().(x$1) => param x$1: Refl[C] -_empty_/Enums.`<:<`.Refl.unapply().[C] => typeparam C +_empty_/Enums.`<:<`.Refl.unapply().[C] => typeparam C _empty_/Enums.`<:<`.`given_<:<_T_T`(). => final implicit given method given_<:<_T_T [typeparam T ]: <:<[T, T] -_empty_/Enums.`<:<`.`given_<:<_T_T`().[T] => typeparam T +_empty_/Enums.`<:<`.`given_<:<_T_T`().[T] => typeparam T _empty_/Enums.`<:<`.fromOrdinal(). => method fromOrdinal (param ordinal: Int): <:<[_, _] forSome { type _ ; type _ } _empty_/Enums.`<:<`.fromOrdinal().(ordinal) => param ordinal: Int _empty_/Enums.some1. => val method some1 Option[Int] _empty_/Enums.unwrap(). => method unwrap [typeparam A , typeparam B ](param opt: Option[A])(implicit given param ev: <:<[A, Option[B]]): Option[B] _empty_/Enums.unwrap().(ev) => implicit given param ev: <:<[A, Option[B]] _empty_/Enums.unwrap().(opt) => param opt: Option[A] -_empty_/Enums.unwrap().[A] => typeparam A -_empty_/Enums.unwrap().[B] => typeparam B +_empty_/Enums.unwrap().[A] => typeparam A +_empty_/Enums.unwrap().[B] => typeparam B local0 => param x: Option[B] Occurrences: @@ -1525,7 +1530,7 @@ Symbols: ext/DeckUsage. => final object DeckUsage extends Object { self: DeckUsage.type => +2 decls } ext/DeckUsage.deck. => val method deck Deck ext/Extension$package. => final package object ext extends Object { self: ext.type { opaque type Deck } => +9 decls } -ext/Extension$package.Deck# => opaque type Deck +ext/Extension$package.Deck# => opaque type Deck ext/Extension$package.Deck. => final object Deck extends Object { self: Deck.type => +2 decls } ext/Extension$package.Deck.fooSize(). => method fooSize (param data: Deck): Int ext/Extension$package.Deck.fooSize().(data) => param data: Deck @@ -1539,18 +1544,18 @@ ext/Extension$package.foo().(s) => param s: String ext/Extension$package.readInto(). => method readInto [typeparam T ](param s: String)(implicit given param x$2: Read[T]): Option[T] ext/Extension$package.readInto().(s) => param s: String ext/Extension$package.readInto().(x$2) => implicit given param x$2: Read[T] -ext/Extension$package.readInto().[T] => typeparam T +ext/Extension$package.readInto().[T] => typeparam T ext/Functor# => trait Functor [typeparam F [type _ ]] extends Object { self: Functor[F] => +3 decls } ext/Functor#[F] => typeparam F [type _ ] -ext/Functor#[F][_] => type _ +ext/Functor#[F][_] => type _ ext/Functor#``(). => primary ctor [typeparam F [type _ ]](): Functor[F] ext/Functor#map(). => abstract method map [typeparam T , typeparam U ](param t: F[T])(param f: Function1[T, U]): F[U] ext/Functor#map().(f) => param f: Function1[T, U] ext/Functor#map().(t) => param t: F[T] -ext/Functor#map().[T] => typeparam T -ext/Functor#map().[U] => typeparam U +ext/Functor#map().[T] => typeparam T +ext/Functor#map().[U] => typeparam U ext/Read# => trait Read [covariant typeparam T ] extends Object { self: Read[T] => +3 decls } -ext/Read#[T] => covariant typeparam T +ext/Read#[T] => covariant typeparam T ext/Read#``(). => primary ctor [covariant typeparam T ](): Read[T] ext/Read#fromString(). => abstract method fromString (param s: String): Option[T] ext/Read#fromString().(s) => param s: String @@ -1731,7 +1736,7 @@ Synthetics => 3 entries Symbols: a/b/Givens. => final object Givens extends Object { self: Givens.type => +13 decls } a/b/Givens.Monoid# => trait Monoid [typeparam A ] extends Object { self: Monoid[A] => +4 decls } -a/b/Givens.Monoid#[A] => typeparam A +a/b/Givens.Monoid#[A] => typeparam A a/b/Givens.Monoid#``(). => primary ctor [typeparam A ](): Monoid[A] a/b/Givens.Monoid#combine(). => abstract method combine (param x: A)(param y: A): A a/b/Givens.Monoid#combine().(x) => param x: A @@ -1739,7 +1744,7 @@ a/b/Givens.Monoid#combine().(y) => param y: A a/b/Givens.Monoid#empty(). => abstract method empty => A a/b/Givens.foo(). => method foo [typeparam A ](implicit given param A: Monoid[A]): A a/b/Givens.foo().(A) => implicit given param A: Monoid[A] -a/b/Givens.foo().[A] => typeparam A +a/b/Givens.foo().[A] => typeparam A a/b/Givens.given_Monoid_String. => final implicit given object given_Monoid_String extends Object with Monoid[String] { self: given_Monoid_String.type => +3 decls } a/b/Givens.given_Monoid_String.combine(). => method combine (param x: String)(param y: String): String <: a/b/Givens.Monoid#combine(). a/b/Givens.given_Monoid_String.combine().(x) => param x: String @@ -1754,13 +1759,13 @@ a/b/Givens.int2String#apply().(x) => param x: Int a/b/Givens.int2String(). => final implicit given inline macro int2String => int2String a/b/Givens.sayGoodbye(). => method sayGoodbye [typeparam B ](param any: B): String a/b/Givens.sayGoodbye().(any) => param any: B -a/b/Givens.sayGoodbye().[B] => typeparam B +a/b/Givens.sayGoodbye().[B] => typeparam B a/b/Givens.sayHello(). => method sayHello [typeparam A ](param any: A): String a/b/Givens.sayHello().(any) => param any: A -a/b/Givens.sayHello().[A] => typeparam A +a/b/Givens.sayHello().[A] => typeparam A a/b/Givens.saySoLong(). => method saySoLong [typeparam B ](param any: B): String a/b/Givens.saySoLong().(any) => param any: B -a/b/Givens.saySoLong().[B] => typeparam B +a/b/Givens.saySoLong().[B] => typeparam B a/b/Givens.soLong1. => val method soLong1 String Occurrences: @@ -1868,7 +1873,7 @@ example/ImplicitConversion#tuple. => val method tuple Tuple2[Int, Int] example/ImplicitConversion#x. => val method x Int example/ImplicitConversion. => final object ImplicitConversion extends Object { self: ImplicitConversion.type => +6 decls } example/ImplicitConversion.newAny2stringadd# => final implicit class newAny2stringadd [typeparam A ] extends AnyVal { self: newAny2stringadd[A] => +4 decls } -example/ImplicitConversion.newAny2stringadd#[A] => typeparam A +example/ImplicitConversion.newAny2stringadd#[A] => typeparam A example/ImplicitConversion.newAny2stringadd#`+`(). => method + (param other: String): String example/ImplicitConversion.newAny2stringadd#`+`().(other) => param other: String example/ImplicitConversion.newAny2stringadd#``(). => primary ctor [typeparam A ](param self: A): newAny2stringadd[A] @@ -1876,7 +1881,7 @@ example/ImplicitConversion.newAny2stringadd#``().(self) => param self: A example/ImplicitConversion.newAny2stringadd#self. => private val method self A example/ImplicitConversion.newAny2stringadd(). => final implicit method newAny2stringadd [typeparam A ](param self: A): newAny2stringadd[A] example/ImplicitConversion.newAny2stringadd().(self) => param self: A -example/ImplicitConversion.newAny2stringadd().[A] => typeparam A +example/ImplicitConversion.newAny2stringadd().[A] => typeparam A example/ImplicitConversion.newAny2stringadd. => final object newAny2stringadd extends Object { self: newAny2stringadd.type => +2 decls } Occurrences: @@ -2071,6 +2076,7 @@ Text => empty Language => Scala Symbols => 45 entries Occurrences => 66 entries +Diagnostics => 1 entries Synthetics => 3 entries Symbols: @@ -2088,7 +2094,7 @@ givens/InventedNames$package.given_Double(). => final implicit given method give givens/InventedNames$package.given_Double().(x$1) => implicit given param x$1: Int givens/InventedNames$package.given_Float. => final implicit lazy val given method given_Float Float givens/InventedNames$package.given_List_T(). => final implicit given method given_List_T [typeparam T ]: List[T] -givens/InventedNames$package.given_List_T().[T] => typeparam T +givens/InventedNames$package.given_List_T().[T] => typeparam T givens/InventedNames$package.given_String. => final implicit lazy val given method given_String String givens/InventedNames$package.given_X. => final implicit given object given_X extends Object with X { self: given_X.type => +2 decls } givens/InventedNames$package.given_X.doX(). => method doX => Int <: givens/X#doX(). @@ -2100,11 +2106,11 @@ givens/InventedNames$package.given_Y#x$1. => protected implicit val given method givens/InventedNames$package.given_Y(). => final implicit given method given_Y (implicit given param x$1: X): given_Y givens/InventedNames$package.given_Y().(x$1) => implicit given param x$1: X givens/InventedNames$package.given_Z_T# => implicit given class given_Z_T [typeparam T ] extends Object with Z[T] { self: given_Z_T[T] => +3 decls } -givens/InventedNames$package.given_Z_T#[T] => typeparam T +givens/InventedNames$package.given_Z_T#[T] => typeparam T givens/InventedNames$package.given_Z_T#``(). => primary ctor [typeparam T ](): given_Z_T[T] givens/InventedNames$package.given_Z_T#doZ(). => method doZ => List[T] <: givens/Z#doZ(). givens/InventedNames$package.given_Z_T(). => final implicit given method given_Z_T [typeparam T ]: given_Z_T[T] -givens/InventedNames$package.given_Z_T().[T] => typeparam T +givens/InventedNames$package.given_Z_T().[T] => typeparam T givens/InventedNames$package.intValue. => final implicit lazy val given method intValue Int givens/InventedNames$package.x. => val method x given_X.type givens/InventedNames$package.y. => val method y given_Y @@ -2116,7 +2122,7 @@ givens/Y# => trait Y extends Object { self: Y => +2 decls } givens/Y#``(). => primary ctor (): Y givens/Y#doY(). => abstract method doY => String givens/Z# => trait Z [typeparam T ] extends Object { self: Z[T] => +3 decls } -givens/Z#[T] => typeparam T +givens/Z#[T] => typeparam T givens/Z#``(). => primary ctor [typeparam T ](): Z[T] givens/Z#doZ(). => abstract method doZ => List[T] @@ -2188,6 +2194,9 @@ Occurrences: [41:8..41:17): given_Z_T -> givens/InventedNames$package.given_Z_T(). [41:18..41:24): String -> scala/Predef.String# +Diagnostics: +[24:13..24:13): [warning] unused implicit parameter + Synthetics: [24:0..24:0): => *(x$1) [34:8..34:20):given_Double => *(intValue) @@ -2261,7 +2270,7 @@ Symbols: example/Local# => class Local extends Object { self: Local => +2 decls } example/Local#``(). => primary ctor (): Local example/Local#a(). => method a (): Int -local0 => typeparam A +local0 => typeparam A local1 => param a: A local2 => local id: [typeparam A ](param a: A): A @@ -2326,10 +2335,10 @@ example/MatchType$package.Concat# => type Concat [typeparam Xs <: Tuple, covari example/MatchType$package.Concat#[Xs] => typeparam Xs <: Tuple example/MatchType$package.Concat#[Ys] => covariant typeparam Ys <: Tuple example/MatchType$package.Elem# => type Elem [typeparam X ] = X match { String => Char, Array[t] => t, Iterable[t] => t } -example/MatchType$package.Elem#[X] => typeparam X -local0 => type t -local1 => type t -local2 => type x +example/MatchType$package.Elem#[X] => typeparam X +local0 => type t +local1 => type t +local2 => type x local3 => type xs <: Tuple Occurrences: @@ -2569,11 +2578,11 @@ Occurrences => 156 entries Symbols: example/Methods# => class Methods [typeparam T ] extends Object { self: Methods[T] => +44 decls } example/Methods#AList# => type AList [typeparam T ] = List[T] -example/Methods#AList#[T] => typeparam T +example/Methods#AList#[T] => typeparam T example/Methods#List# => class List [typeparam T ] extends Object { self: List[T] => +2 decls } -example/Methods#List#[T] => typeparam T +example/Methods#List#[T] => typeparam T example/Methods#List#``(). => primary ctor [typeparam T ](): List[T] -example/Methods#[T] => typeparam T +example/Methods#[T] => typeparam T example/Methods#``(). => primary ctor [typeparam T ](): Methods[T] example/Methods#`m8().`(). => method m8(). (): Nothing example/Methods#`m9().`# => class m9(). extends Object { self: m9(). => +1 decls } @@ -2601,7 +2610,7 @@ example/Methods#m7(). => method m7 [typeparam U ](param c: Methods[T], param l: example/Methods#m7().(c) => param c: Methods[T] example/Methods#m7().(evidence$1) => implicit param evidence$1: Ordering[U] example/Methods#m7().(l) => param l: List[U] -example/Methods#m7().[U] => typeparam U +example/Methods#m7().[U] => typeparam U example/Methods#m9(). => method m9 (param x: m9().): Nothing example/Methods#m9().(x) => param x: m9(). example/Methods#m10(). => method m10 (param x: List[T]): Nothing @@ -2961,18 +2970,18 @@ Occurrences => 18 entries Symbols: _empty_/NewModifiers$package. => final package object _empty_ extends Object { self: _empty_.type { opaque type OpaqueB } => +2 decls } -_empty_/NewModifiers$package.OpaqueB# => opaque type OpaqueB +_empty_/NewModifiers$package.OpaqueB# => opaque type OpaqueB _empty_/NewModifiers. => final object NewModifiers extends Object { self: NewModifiers.type { opaque type A } => +3 decls } -_empty_/NewModifiers.A# => opaque type A +_empty_/NewModifiers.A# => opaque type A _empty_/NewModifiers.foo. => val inline method foo "foo" _empty_/NewModifiersClass# => opaque class NewModifiersClass extends Object { self: Any { opaque type C } & NewModifiersClass => +5 decls } -_empty_/NewModifiersClass#C# => opaque type C +_empty_/NewModifiersClass#C# => opaque type C _empty_/NewModifiersClass#Nested# => opaque class Nested extends Object { self: Any { opaque type NestedOpaque } & Nested => +2 decls } -_empty_/NewModifiersClass#Nested#NestedOpaque# => opaque type NestedOpaque +_empty_/NewModifiersClass#Nested#NestedOpaque# => opaque type NestedOpaque _empty_/NewModifiersClass#Nested#``(). => primary ctor (): Nested _empty_/NewModifiersClass#``(). => primary ctor (): NewModifiersClass _empty_/NewModifiersTrait# => opaque trait NewModifiersTrait extends Object { self: Any { opaque type D } & NewModifiersTrait => +2 decls } -_empty_/NewModifiersTrait#D# => opaque type D +_empty_/NewModifiersTrait#D# => opaque type D _empty_/NewModifiersTrait#``(). => primary ctor (): NewModifiersTrait Occurrences: @@ -3060,13 +3069,13 @@ Occurrences => 49 entries Symbols: prefixes/C# => class C extends Object { self: C => +6 decls } prefixes/C#N. => final object N extends Object { self: N.type => +2 decls } -prefixes/C#N.U# => type U -prefixes/C#T# => type T +prefixes/C#N.U# => type U +prefixes/C#T# => type T prefixes/C#``(). => primary ctor (): C prefixes/C#k1(). => method k1 => U prefixes/C#m1(). => method m1 => T prefixes/M. => final object M extends Object { self: M.type => +3 decls } -prefixes/M.T# => type T +prefixes/M.T# => type T prefixes/M.n1(). => method n1 => T prefixes/O. => final object O extends C { self: O.type => +2 decls } prefixes/O.o1(). => method o1 => O.this.T @@ -3143,13 +3152,13 @@ Synthetics => 3 entries Symbols: example/C# => class C extends Object { self: C => +3 decls } -example/C#T1# => type T1 -example/C#T2# => type T2 +example/C#T1# => type T1 +example/C#T2# => type T2 example/C#``(). => primary ctor (): C example/PickOneRefinement_1# => class PickOneRefinement_1 [typeparam S <: SpecialRefinement { abstract method pickOne [typeparam T ](param as: T*): Option[String] }] extends Object { self: PickOneRefinement_1[S] => +3 decls } example/PickOneRefinement_1#[S] => typeparam S <: SpecialRefinement { abstract method pickOne [typeparam T ](param as: T*): Option[String] } example/PickOneRefinement_1#[S](as) => param as: T* -example/PickOneRefinement_1#[S][T] => typeparam T +example/PickOneRefinement_1#[S][T] => typeparam T example/PickOneRefinement_1#``(). => primary ctor [typeparam S <: SpecialRefinement { abstract method pickOne [typeparam T ](param as: T*): Option[String] }](): PickOneRefinement_1[S] example/PickOneRefinement_1#run(). => method run (param s: S, param as: String*): Option[String] example/PickOneRefinement_1#run().(as) => param as: String* @@ -3158,7 +3167,7 @@ example/PolyHolder# => trait PolyHolder extends Object { self: PolyHolder => +2 example/PolyHolder#``(). => primary ctor (): PolyHolder example/PolyHolder#foo(). => abstract method foo [typeparam T ](param t: T): Any example/PolyHolder#foo().(t) => param t: T -example/PolyHolder#foo().[T] => typeparam T +example/PolyHolder#foo().[T] => typeparam T example/RecOrRefined$package. => final package object example extends Object { self: example.type => +9 decls } example/RecOrRefined$package.C2# => type C2 = C { type T2 = T1 <: example/C#T2#; type T1 <: example/C#T1# } example/RecOrRefined$package.Person# => type Person = Record { abstract val method age Int; abstract val method name String } @@ -3172,9 +3181,9 @@ example/RecOrRefined$package.m4(). => method m4 (param x: PolyHolder { abstract example/RecOrRefined$package.m4().(x) => param x: PolyHolder { abstract method foo [typeparam T ](param t: T): T <: example/PolyHolder#foo(). } example/RecOrRefined$package.m5(). => method m5 [typeparam Z ](param x: Int): PolyHolder { abstract method foo [typeparam T ](param t: T): T <: example/PolyHolder#foo(). } example/RecOrRefined$package.m5().(x) => param x: Int -example/RecOrRefined$package.m5().[Z] => typeparam Z +example/RecOrRefined$package.m5().[Z] => typeparam Z example/RecOrRefined$package.m6# => type m6 [typeparam X ] = PolyHolder { abstract method foo [typeparam T ](param t: T): T <: example/PolyHolder#foo(). } -example/RecOrRefined$package.m6#[X] => typeparam X +example/RecOrRefined$package.m6#[X] => typeparam X example/Record# => class Record extends Object with Selectable { self: Record => +4 decls } example/Record#``(). => primary ctor (param elems: Tuple2[String, Any]*): Record example/Record#``().(elems) => param elems: Tuple2[String, Any]* @@ -3186,9 +3195,9 @@ example/SpecialRefinement# => trait SpecialRefinement extends Object { self: Spe example/SpecialRefinement#``(). => primary ctor (): SpecialRefinement example/SpecialRefinement#pickOne(). => abstract method pickOne [typeparam T ](param as: T*): Option[Any] example/SpecialRefinement#pickOne().(as) => param as: T* -example/SpecialRefinement#pickOne().[T] => typeparam T +example/SpecialRefinement#pickOne().[T] => typeparam T local0 => abstract method pickOne [typeparam T ](param as: T*): Option[String] -local1 => typeparam T +local1 => typeparam T local2 => param as: T* local3 => abstract method pickOne [typeparam T ](param as: T*): Option[String] <: example/SpecialRefinement#pickOne(). local4 => abstract val method x Int @@ -3196,14 +3205,14 @@ local5 => abstract val method x Int local6 => abstract method y => Int local7 => abstract val method x Int local8 => abstract method y => Int -local9 => type z -local10 => typeparam T +local9 => type z +local10 => typeparam T local11 => param t: T local12 => abstract method foo [typeparam T ](param t: T): T <: example/PolyHolder#foo(). -local13 => typeparam T +local13 => typeparam T local14 => param t: T local15 => abstract method foo [typeparam T ](param t: T): T <: example/PolyHolder#foo(). -local16 => typeparam T +local16 => typeparam T local17 => param t: T local18 => abstract method foo [typeparam T ](param t: T): T <: example/PolyHolder#foo(). local19 => abstract val method name String @@ -3509,7 +3518,7 @@ example/Synthetic#Contexts.m4(). => method m4 => Nothing example/Synthetic#F# => class F extends Object { self: F => +1 decls } example/Synthetic#F#``(). => primary ctor (): F example/Synthetic#J# => class J [typeparam T ] extends Object { self: J[T] => +4 decls } -example/Synthetic#J#[T] => typeparam T +example/Synthetic#J#[T] => typeparam T example/Synthetic#J#``(). => primary ctor [typeparam T ]()(implicit param evidence$1: Manifest[T]): J[T] example/Synthetic#J#``().(evidence$1) => implicit param evidence$1: Manifest[T] example/Synthetic#J#arr. => val method arr Array[T] @@ -3724,6 +3733,11 @@ Occurrences: [68:18..68:24): impure -> local20 [68:30..68:31): s -> local16 +Diagnostics: +[19:21..19:22): [warning] unused pattern variable +[41:4..41:5): [warning] unused pattern variable +[63:10..63:11): [warning] unused explicit parameter + Synthetics: [5:2..5:13):List(1).map => *[Int] [5:2..5:6):List => *.apply[Int] @@ -4209,16 +4223,15 @@ Text => empty Language => Scala Symbols => 8 entries Occurrences => 18 entries -Diagnostics => 1 entries Symbols: _empty_/Test_depmatch. => final object Test_depmatch extends Object { self: Test_depmatch.type => +4 decls } _empty_/Test_depmatch.Bar# => type Bar [typeparam T ] = T match { Unit => Unit } -_empty_/Test_depmatch.Bar#[T] => typeparam T +_empty_/Test_depmatch.Bar#[T] => typeparam T _empty_/Test_depmatch.Foo# => type Foo = Int { type U } _empty_/Test_depmatch.baz(). => inline macro baz (param foo: Foo): Unit _empty_/Test_depmatch.baz().(foo) => param foo: Foo -local0 => type U +local0 => type U local1 => val local v: Bar[foo.U] Occurrences: @@ -4241,9 +4254,6 @@ Occurrences: [6:19..6:20): U -> local0 [6:24..6:27): ??? -> scala/Predef.`???`(). -Diagnostics: -[6:8..6:9): [warning] unused local definition - expect/example-dir/FileInDir.scala ---------------------------------- @@ -4277,7 +4287,7 @@ Occurrences => 33 entries Symbols: exports/example/Codec# => trait Codec [typeparam T ] extends Object with Decoder[T] with Encoder[T] { self: Codec[T] => +6 decls } -exports/example/Codec#[T] => typeparam T +exports/example/Codec#[T] => typeparam T exports/example/Codec#``(). => primary ctor [typeparam T ](param decode: Decoder[T], param encode: Encoder[T]): Codec[T] exports/example/Codec#``().(decode) => param decode: Decoder[T] exports/example/Codec#``().(encode) => param encode: Encoder[T] @@ -4288,12 +4298,12 @@ exports/example/Codec#encode(). => final method encode (param t: T): Array[Byte] exports/example/Codec#encode().(t) => param t: T exports/example/Codec#encode. => private[this] val method encode Encoder[T] exports/example/Decoder# => trait Decoder [covariant typeparam T ] extends Object { self: Decoder[T] => +3 decls } -exports/example/Decoder#[T] => covariant typeparam T +exports/example/Decoder#[T] => covariant typeparam T exports/example/Decoder#``(). => primary ctor [covariant typeparam T ](): Decoder[T] exports/example/Decoder#decode(). => abstract method decode (param a: Array[Byte]): T exports/example/Decoder#decode().(a) => param a: Array[Byte] exports/example/Encoder# => trait Encoder [contravariant typeparam T ] extends Object { self: Encoder[T] => +3 decls } -exports/example/Encoder#[T] => contravariant typeparam T +exports/example/Encoder#[T] => contravariant typeparam T exports/example/Encoder#``(). => primary ctor [contravariant typeparam T ](): Encoder[T] exports/example/Encoder#encode(). => abstract method encode (param t: T): Array[Byte] exports/example/Encoder#encode().(t) => param t: T @@ -4347,11 +4357,11 @@ Occurrences => 5 entries Symbols: exports/`exports-package$package`. => final package object exports extends Object { self: exports.type => +4 decls } exports/`exports-package$package`.Codec# => final type Codec [typeparam T ] = Codec[T] -exports/`exports-package$package`.Codec#[T] => typeparam T +exports/`exports-package$package`.Codec#[T] => typeparam T exports/`exports-package$package`.Decoder# => final type Decoder [typeparam T ] = Decoder[T] -exports/`exports-package$package`.Decoder#[T] => typeparam T +exports/`exports-package$package`.Decoder#[T] => typeparam T exports/`exports-package$package`.Encoder# => final type Encoder [typeparam T ] = Encoder[T] -exports/`exports-package$package`.Encoder#[T] => typeparam T +exports/`exports-package$package`.Encoder#[T] => typeparam T Occurrences: [0:8..0:15): exports <- exports/ @@ -4393,35 +4403,35 @@ Occurrences => 54 entries Symbols: hk/EitherMonad# => class EitherMonad [typeparam T ] extends Object with Monad[[E] =>> Either[T, E]] { self: EitherMonad[T] => +2 decls } -hk/EitherMonad#[E] => typeparam E -hk/EitherMonad#[T] => typeparam T +hk/EitherMonad#[E] => typeparam E +hk/EitherMonad#[T] => typeparam T hk/EitherMonad#``(). => primary ctor [typeparam T ](): EitherMonad[T] -hk/EitherMonad#``().[E] => typeparam E +hk/EitherMonad#``().[E] => typeparam E hk/Monad# => trait Monad [typeparam M [type _ ]] extends Object { self: Monad[M] => +4 decls } hk/Monad#[M] => typeparam M [type _ ] -hk/Monad#[M][_] => type _ +hk/Monad#[M][_] => type _ hk/Monad#``(). => primary ctor [typeparam M [type _ ]](): Monad[M] hk/Monad#flatMap(). => method flatMap [typeparam A , typeparam B ](param m: M[A])(param f: Function1[A, M[B]]): M[B] hk/Monad#flatMap().(f) => param f: Function1[A, M[B]] hk/Monad#flatMap().(m) => param m: M[A] -hk/Monad#flatMap().[A] => typeparam A -hk/Monad#flatMap().[B] => typeparam B +hk/Monad#flatMap().[A] => typeparam A +hk/Monad#flatMap().[B] => typeparam B hk/Monad#pure(). => method pure [typeparam A ](param a: A): M[A] hk/Monad#pure().(a) => param a: A -hk/Monad#pure().[A] => typeparam A +hk/Monad#pure().[A] => typeparam A hk/hk$package. => final package object hk extends Object { self: hk.type => +5 decls } hk/hk$package.Id# => type Id [typeparam A ] = A -hk/hk$package.Id#[A] => typeparam A +hk/hk$package.Id#[A] => typeparam A hk/hk$package.MapEither# => type MapEither [typeparam K ] = [L] =>> [R] =>> Map[K, Either[L, R]] -hk/hk$package.MapEither#[K] => typeparam K -hk/hk$package.MapEither#[L] => typeparam L -hk/hk$package.MapEither#[R] => typeparam R +hk/hk$package.MapEither#[K] => typeparam K +hk/hk$package.MapEither#[L] => typeparam L +hk/hk$package.MapEither#[R] => typeparam R hk/hk$package.MapKV# => type MapKV [typeparam K ] = [V] =>> Map[K, V] -hk/hk$package.MapKV#[K] => typeparam K -hk/hk$package.MapKV#[V] => typeparam V +hk/hk$package.MapKV#[K] => typeparam K +hk/hk$package.MapKV#[V] => typeparam V hk/hk$package.MapV# => type MapV [type _ ] = [V] =>> Map[String, V] -hk/hk$package.MapV#[V] => typeparam V -hk/hk$package.MapV#[_] => type _ +hk/hk$package.MapV#[V] => typeparam V +hk/hk$package.MapV#[_] => type _ Occurrences: [0:8..0:10): hk <- hk/ @@ -4562,6 +4572,7 @@ Text => empty Language => Scala Symbols => 24 entries Occurrences => 63 entries +Diagnostics => 2 entries Symbols: _empty_/Copy# => trait Copy [typeparam In <: Txn[In], typeparam Out <: Txn[Out]] extends Object { self: Copy[In, Out] => +5 decls } @@ -4654,6 +4665,10 @@ Occurrences: [14:8..14:15): println -> scala/Predef.println(+1). [17:4..17:7): out -> local0 +Diagnostics: +[13:12..13:17): [warning] unused pattern variable +[13:28..13:34): [warning] unused pattern variable + expect/inlineconsume.scala -------------------------- @@ -4756,11 +4771,11 @@ _empty_/Concrete#``(). => primary ctor (): Concrete _empty_/Concrete#nullary2(). => method nullary2 => Int <: _empty_/NullaryTest#nullary2(). _empty_/Concrete#nullary3(). => method nullary3 => List[Int] <: _empty_/NullaryTest#nullary3(). _empty_/NullaryTest# => abstract class NullaryTest [typeparam T , typeparam m [typeparam s ]] extends Object { self: NullaryTest[T, m] => +9 decls } -_empty_/NullaryTest#[T] => typeparam T +_empty_/NullaryTest#[T] => typeparam T _empty_/NullaryTest#[m] => typeparam m [typeparam s ] -_empty_/NullaryTest#[m][s] => typeparam s +_empty_/NullaryTest#[m][s] => typeparam s _empty_/NullaryTest#``(). => primary ctor [typeparam T , typeparam m [typeparam s ]](): NullaryTest[T, m] -_empty_/NullaryTest#``().[m][s] => typeparam s +_empty_/NullaryTest#``().[m][s] => typeparam s _empty_/NullaryTest#nullary(). => method nullary => String _empty_/NullaryTest#nullary2(). => abstract method nullary2 => T _empty_/NullaryTest#nullary3(). => abstract method nullary3 => m[T] @@ -4948,7 +4963,7 @@ Text => empty Language => Scala Symbols => 50 entries Occurrences => 78 entries -Diagnostics => 4 entries +Diagnostics => 6 entries Synthetics => 2 entries Symbols: @@ -4964,9 +4979,9 @@ flags/p/package.AA#x. => private[this] val method x Int flags/p/package.AA#y. => val method y Int flags/p/package.AA#z(). => var method z Int flags/p/package.C# => abstract class C [covariant typeparam T , contravariant typeparam U , typeparam V ] extends Object { self: C[T, U, V] => +10 decls } -flags/p/package.C#[T] => covariant typeparam T -flags/p/package.C#[U] => contravariant typeparam U -flags/p/package.C#[V] => typeparam V +flags/p/package.C#[T] => covariant typeparam T +flags/p/package.C#[U] => contravariant typeparam U +flags/p/package.C#[V] => typeparam V flags/p/package.C#``(). => primary ctor [covariant typeparam T , contravariant typeparam U , typeparam V ](param x: T, param y: U, param z: V): C[T, U, V] flags/p/package.C#``().(x) => param x: T flags/p/package.C#``().(y) => param y: U @@ -4979,11 +4994,11 @@ flags/p/package.C#x. => private[this] val method x T flags/p/package.C#y. => private[this] val method y U flags/p/package.C#z. => private[this] val method z V flags/p/package.S# => class S [@specialized typeparam T ] extends Object { self: S[T] => +2 decls } -flags/p/package.S#[T] => @specialized typeparam T +flags/p/package.S#[T] => @specialized typeparam T flags/p/package.S#``(). => primary ctor [@specialized typeparam T ](): S[T] flags/p/package.T1# => type T1 = Int flags/p/package.T2# => type T2 [typeparam T ] = S[T] -flags/p/package.T2#[T] => typeparam T +flags/p/package.T2#[T] => typeparam T flags/p/package.U# => type U <: Int flags/p/package.V# => type V >: Int flags/p/package.X. => final case object X extends Object with Product with Serializable { self: X.type => +1 decls } @@ -4994,14 +5009,14 @@ flags/p/package.Z#``(). => primary ctor (): Z flags/p/package.`y_=`(). => protected var method y_= (param x$1: Int): Unit flags/p/package.`y_=`().(x$1) => param x$1: Int flags/p/package.m(). => macro m [typeparam TT ]: Int -flags/p/package.m().[TT] => typeparam TT +flags/p/package.m().[TT] => typeparam TT flags/p/package.x. => private[flags/p/] lazy val method x Int flags/p/package.xs1. => val method xs1 Nothing flags/p/package.y(). => protected implicit var method y Int flags/p/package.z(). => method z (param pp: Int): Int flags/p/package.z().(pp) => param pp: Int local0 => val local xs2: Nothing -local1 => type t +local1 => type t Occurrences: [0:8..0:13): flags <- flags/ @@ -5088,6 +5103,8 @@ Diagnostics: [9:36..9:37): [warning] unused explicit parameter [9:42..9:43): [warning] unused explicit parameter [21:11..21:12): [warning] unused explicit parameter +[24:24..24:27): [warning] unused pattern variable +[25:27..25:28): [warning] unused pattern variable Synthetics: [23:6..23:10):List => *.unapplySeq[Nothing] @@ -5114,7 +5131,7 @@ local3 => final class $anon extends Object { self: $anon => +2 decls } local5 => final class $anon extends M with N { self: $anon => +1 decls } local7 => method k => Int local8 => final class $anon extends M with N { self: $anon => +2 decls } -local10 => typeparam T +local10 => typeparam T local11 => type L [typeparam T ] = List[T] types/B# => class B extends Object { self: B => +1 decls } types/B#``(). => primary ctor (): B @@ -5159,7 +5176,7 @@ types/Test.C#ClassInfoType2# => class ClassInfoType2 extends B { self: ClassInfo types/Test.C#ClassInfoType2#``(). => primary ctor (): ClassInfoType2 types/Test.C#ClassInfoType2#x(). => method x => Int types/Test.C#ClassInfoType3# => trait ClassInfoType3 [typeparam T ] extends Object { self: ClassInfoType3[T] => +2 decls } -types/Test.C#ClassInfoType3#[T] => typeparam T +types/Test.C#ClassInfoType3#[T] => typeparam T types/Test.C#ClassInfoType3#``(). => primary ctor [typeparam T ](): ClassInfoType3[T] types/Test.C#Either. => val method Either Either.type types/Test.C#MethodType. => final object MethodType extends Object { self: MethodType.type => +7 decls } @@ -5169,7 +5186,7 @@ types/Test.C#MethodType.m5(). => method m5 (param x: Int): Int types/Test.C#MethodType.m5().(x) => param x: Int types/Test.C#MethodType.m6(). => method m6 [typeparam T ](param x: T): T types/Test.C#MethodType.m6().(x) => param x: T -types/Test.C#MethodType.m6().[T] => typeparam T +types/Test.C#MethodType.m6().[T] => typeparam T types/Test.C#MethodType.x1(). => method x1 => Int types/Test.C#MethodType.x2(). => method x2 => Int types/Test.C#RepeatedType# => case class RepeatedType extends Object with Product with Serializable { self: RepeatedType => +4 decls } @@ -5186,15 +5203,15 @@ types/Test.C#RepeatedType.toString(). => method toString => String <: scala/Any# types/Test.C#RepeatedType.unapplySeq(). => method unapplySeq (param x$1: RepeatedType): RepeatedType types/Test.C#RepeatedType.unapplySeq().(x$1) => param x$1: RepeatedType types/Test.C#TypeType. => final object TypeType extends Object { self: TypeType.type => +6 decls } -types/Test.C#TypeType.T1# => type T1 +types/Test.C#TypeType.T1# => type T1 types/Test.C#TypeType.T4# => type T4 = C types/Test.C#TypeType.T5# => type T5 [typeparam U ] = U -types/Test.C#TypeType.T5#[U] => typeparam U +types/Test.C#TypeType.T5#[U] => typeparam U types/Test.C#TypeType.m2(). => method m2 [typeparam T2 = C]: Nothing types/Test.C#TypeType.m2().[T2] => typeparam T2 = C types/Test.C#TypeType.m3(). => method m3 [typeparam M3 [type _ ]]: Nothing types/Test.C#TypeType.m3().[M3] => typeparam M3 [type _ ] -types/Test.C#TypeType.m3().[M3][_] => type _ +types/Test.C#TypeType.m3().[M3][_] => type _ types/Test.C#``(). => primary ctor (): C types/Test.C#annType1. => val method annType1 T @ann[T] types/Test.C#annType2. => val method annType2 T @ann1 @ann2 @@ -5217,7 +5234,7 @@ types/Test.C#thisType1. => val method thisType1 C.this.type types/Test.C#thisType2. => val method thisType2 C.this.type types/Test.C#typeLambda1(). => method typeLambda1 [typeparam M [type _ ]]: Nothing types/Test.C#typeLambda1().[M] => typeparam M [type _ ] -types/Test.C#typeLambda1().[M][_] => type _ +types/Test.C#typeLambda1().[M][_] => type _ types/Test.C#typeRef1. => val method typeRef1 C types/Test.C#typeRef2. => val method typeRef2 p.C types/Test.C#typeRef3. => val method typeRef3 T#C @@ -5242,7 +5259,7 @@ types/Test.N# => trait N extends Object { self: N => +2 decls } types/Test.N#``(). => primary ctor (): N types/Test.N#n(). => method n => Int types/ann# => class ann [typeparam T ] extends Annotation with StaticAnnotation { self: ann[T] => +3 decls } -types/ann#[T] => typeparam T +types/ann#[T] => typeparam T types/ann#``(). => primary ctor [typeparam T ](param x: T): ann[T] types/ann#``().(x) => param x: T types/ann#x. => private[this] val method x T diff --git a/tests/untried/neg/warn-unused-privates.scala b/tests/untried/neg/warn-unused-privates.scala deleted file mode 100644 index 64e7679f37ac..000000000000 --- a/tests/untried/neg/warn-unused-privates.scala +++ /dev/null @@ -1,105 +0,0 @@ -class Bippy(a: Int, b: Int) { - private def this(c: Int) = this(c, c) // warn - private def bippy(x: Int): Int = bippy(x) // TODO: could warn - private def boop(x: Int) = x + a + b // warn - final private val MILLIS1 = 2000 // no warn, might have been inlined - final private val MILLIS2: Int = 1000 // warn - final private val HI_COMPANION: Int = 500 // no warn, accessed from companion - def hi() = Bippy.HI_INSTANCE -} -object Bippy { - def hi(x: Bippy) = x.HI_COMPANION - private val HI_INSTANCE: Int = 500 // no warn, accessed from instance - private val HEY_INSTANCE: Int = 1000 // warn -} - -class A(val msg: String) -class B1(msg: String) extends A(msg) -class B2(msg0: String) extends A(msg0) -class B3(msg0: String) extends A("msg") - -/*** Early defs warnings disabled primarily due to SI-6595. - * The test case is here to assure we aren't issuing false positives; - * the ones labeled "warn" don't warn. - ***/ -class Boppy extends { - private val hmm: String = "abc" // no warn, used in early defs - private val hom: String = "def" // no warn, used in body - private final val him = "ghi" // no warn, might have been (was) inlined - final val him2 = "ghi" // no warn, same - final val himinline = him - private val hum: String = "jkl" // warn - final val ding = hmm.length -} with Mutable { - val dinger = hom - private val hummer = "def" // warn - - private final val bum = "ghi" // no warn, might have been (was) inlined - final val bum2 = "ghi" // no warn, same -} - -trait Accessors { - private var v1: Int = 0 // warn - private var v2: Int = 0 // warn, never set - private var v3: Int = 0 // warn, never got - private var v4: Int = 0 // no warn - - def bippy(): Int = { - v3 = 5 - v4 = 6 - v2 + v4 - } -} - -trait DefaultArgs { - // warn about default getters for x2 and x3 - private def bippy(x1: Int, x2: Int = 10, x3: Int = 15): Int = x1 + x2 + x3 - - def boppy() = bippy(5, 100, 200) -} - -class Outer { - class Inner -} - -trait Locals { - def f0 = { - var x = 1 // warn - var y = 2 - y = 3 - y + y - } - def f1 = { - val a = new Outer // no warn - val b = new Outer // warn - new a.Inner - } - def f2 = { - var x = 100 // warn about it being a var - x - } -} - -object Types { - private object Dongo { def f = this } // warn - private class Bar1 // warn - private class Bar2 // no warn - private type Alias1 = String // warn - private type Alias2 = String // no warn - def bippo = (new Bar2).toString - - def f(x: Alias2) = x.length - - def l1() = { - object HiObject { def f = this } // warn - class Hi { // warn - def f1: Hi = new Hi - def f2(x: Hi) = x - } - class DingDongDoobie // warn - class Bippy // no warn - type Something = Bippy // no warn - type OtherThing = String // warn - (new Bippy): Something - } -} diff --git a/tests/pos/i15226.scala b/tests/warn/i15226.scala similarity index 100% rename from tests/pos/i15226.scala rename to tests/warn/i15226.scala diff --git a/tests/warn/i15503a.scala b/tests/warn/i15503a.scala index df8691c21a13..40b6c75983bf 100644 --- a/tests/warn/i15503a.scala +++ b/tests/warn/i15503a.scala @@ -1,5 +1,4 @@ -//> using options -Wunused:imports - +//> using options -Wunused:imports -Wconf:origin=Suppressed.*:s object FooUnused: import collection.mutable.Set // warn @@ -68,7 +67,7 @@ object InlineChecks: inline def getSet = Set(1) object InlinedBar: - import collection.mutable.Set // ok + import collection.mutable.Set // warn (don't be fooled by inline expansion) import collection.mutable.Map // warn val a = InlineFoo.getSet @@ -100,20 +99,28 @@ object SomeGivenImports: given String = "foo" /* BEGIN : Check on packages*/ -package testsamepackageimport: - package p { +package nestedpackageimport: + package p: class C - } - - package p { - import p._ // warn - package q { - class U { + package p: + package q: + import p.* // warn + class U: def f = new C - } - } - } -// ----------------------- +package unnestedpackageimport: + package p: + class C + package p.q: + import p.* // nowarn + class U: + def f = new C + +package redundancy: + object redundant: + def f = 42 + import redundancy.* // warn superseded by def in scope + class R: + def g = redundant.f package testpackageimport: package a: @@ -213,7 +220,8 @@ package testImportsInImports: package c: import a.b // OK import b.x // OK - val y = x + import b.x as z // OK + val y = x + z //------------------------------------- package testOnOverloadedMethodsImports: @@ -265,4 +273,51 @@ package foo.test.typeapply.hklamdba.i16680: import foo.IO // OK def f[F[_]]: String = "hello" - def go = f[IO] \ No newline at end of file + def go = f[IO] + +object Selections: + def f(list: List[Int]): Int = + import list.{head => first} // OK + first + + def f2(list: List[Int]): Int = + import list.head // OK + head + + def f3(list: List[Int]): Int = + import list.head // warn + list.head + + object N: + val ns: List[Int] = Nil + + def g(): Int = + import N.ns // OK + ns.head +end Selections + +object `more nestings`: + object Outer: + object Inner: + val thing = 42 + def j() = + import Inner.thing // warn + thing + def k() = + import Inner.thing // warn + Inner.thing + + object Thing: + object Inner: + val thing = 42 + import Inner.thing // warn + def j() = + thing + def k() = + Inner.thing + +object Suppressed: + val suppressed = 42 +object Suppressing: + import Suppressed.* // no warn, see options + def f = 42 diff --git a/tests/warn/i15503b.scala b/tests/warn/i15503b.scala index 7ab86026ff00..0ea110f833f1 100644 --- a/tests/warn/i15503b.scala +++ b/tests/warn/i15503b.scala @@ -117,7 +117,7 @@ package foo.scala2.tests: object Types { def l1() = { - object HiObject { def f = this } // OK + object HiObject { def f = this } // warn class Hi { // warn def f1: Hi = new Hi def f2(x: Hi) = x @@ -141,4 +141,4 @@ package test.foo.twisted.i16682: } isInt - def f = myPackage("42") \ No newline at end of file + def f = myPackage("42") diff --git a/tests/warn/i15503c.scala b/tests/warn/i15503c.scala index a813329da89b..86b972487e17 100644 --- a/tests/warn/i15503c.scala +++ b/tests/warn/i15503c.scala @@ -1,4 +1,4 @@ -//> using options -Wunused:privates -source:3.3 +//> using options -Wunused:privates -source:3.3 trait C class A: @@ -33,17 +33,22 @@ class A: var w = 2 // OK package foo.test.constructors: - case class A private (x:Int) // OK + case class A private (x: Int) // OK class B private (val x: Int) // OK - class C private (private val x: Int) // warn + object B { def default = B(42) } + class C private (private val xy: Int) // warn + object C { def default = C(42) } class D private (private val x: Int): // OK def y = x + object D { def default = D(42) } class E private (private var x: Int): // warn not set def y = x + object E { def default = E(42) } class F private (private var x: Int): // OK def y = x = 3 x + object F { def default = F(42) } package test.foo.i16682: object myPackage: @@ -55,4 +60,13 @@ package test.foo.i16682: case _ => println("NaN") } - def f = myPackage.isInt("42") \ No newline at end of file + def f = myPackage.isInt("42") + +object LazyVals: + import java.util.concurrent.CountDownLatch + + // This trait extends Serializable to fix #16806 that caused a race condition + sealed trait LazyValControlState extends Serializable + + final class Waiting extends CountDownLatch(1), LazyValControlState: + private def writeReplace(): Any = null diff --git a/tests/warn/i15503d.scala b/tests/warn/i15503d.scala index 9a0ba9b2f8dc..494952e2e4b0 100644 --- a/tests/warn/i15503d.scala +++ b/tests/warn/i15503d.scala @@ -1,5 +1,6 @@ -//> using options -Wunused:unsafe-warn-patvars -// todo : change to :patvars +//> using options -Wunused:patvars + +import scala.reflect.Typeable sealed trait Calc sealed trait Const extends Calc @@ -8,23 +9,118 @@ case class S(pred: Const) extends Const case object Z extends Const val a = Sum(S(S(Z)),Z) match { - case Sum(a,Z) => Z // warn + case Sum(x,Z) => Z // warn // case Sum(a @ _,Z) => Z // todo : this should pass in the future - case Sum(a@S(_),Z) => Z // warn - case Sum(a@S(_),Z) => a // warn unreachable - case Sum(a@S(b@S(_)), Z) => a // warn - case Sum(a@S(b@S(_)), Z) => a // warn - case Sum(a@S(b@(S(_))), Z) => Sum(a,b) // warn unreachable + case Sum(x@S(_),Z) => Z // warn + case Sum(x@S(_),Z) => x // warn unreachable + case Sum(x@S(y@S(_)), Z) => x // warn + case Sum(x@S(y@S(_)), Z) => x // warn + case Sum(x@S(y@(S(_))), Z) => Sum(x,y) // warn unreachable case Sum(_,_) => Z // OK case _ => Z // warn unreachable } -// todo : This should pass in the future -// val b = for { -// case Some(x) <- Option(Option(1)) -// } println(s"$x") +case class K(i: Int, j: Int) + +class C(c0: Option[Int], k0: K): + private val Some(c) = c0: @unchecked // warn valdef from pattern + private val K(i, j) = k0 // warn // warn valdefs from pattern (RHS patvars are NoWarn) + val K(v, w) = k0 // nowarn nonprivate + private val K(r, s) = k0 // warn // warn valdefs from pattern + def f(x: Option[Int]) = x match + case Some(y) => true // warn Bind in pattern + case _ => false + def g(ns: List[Int]) = + for x <- ns do println() // warn valdef function param from for + def g1(ns: List[Int]) = + for x <- ns do println(x) // x => println(x) + def h(ns: List[Int]) = + for x <- ns; y = x + 1 // warn tupling from for; x is used, y is unused + do println() + def k(x: Option[K]) = + x match + case Some(K(i, j)) => // nowarn canonical names + case _ => + + val m = Map( + "first" -> Map((true, 1), (false, 2), (true, 3)), + "second" -> Map((true, 1), (false, 2), (true, 3)), + ) + def guardedUse = + m.map: (a, m1) => + for (status, lag) <- m1 if status + yield (a, status, lag) + def guardedUseOnly = + m.map: (a, m1) => + for (status, lag) <- m1 if status + yield (a, lag) + def guardedUseMissing = + m.map: (a, m1) => + for (status, lag) <- m1 // warn + yield (a, lag) + def flatGuardedUse = + for (a, m1) <- m; (status, lag) <- m1 if status + yield (a, status, lag) + def leading = + for _ <- List("42"); i = 1; _ <- List("0", "27")(i) + yield () + def optional = + for case Some(x) <- List(Option(42)) + yield x + def nonoptional = + for case Some(x) <- List(Option(42)) // warn + yield 27 + def optionalName = + for case Some(value) <- List(Option(42)) + yield 27 + + /* + def tester[A](a: A)(using Typeable[K]) = + a match + case S(i, j) => i + j + case _ => 0 + */ + +class Wild: + def f(x: Any) = + x match + case _: Option[?] => true + case _ => false + +def untuple(t: Tuple) = + t match + case Tuple() => + case h *: t => // no warn canonical names taken from tuple element types, (Head, Tail) -> (head, tail) + //case head *: tail => // no warn canonical names taken from tuple element types, (Head, Tail) -> (head, tail) + +// empty case class: +// def equals(other) = other match { case other => true } // exonerated name +object i15967: + sealed trait A[-Z] + final case class B[Y]() extends A[Y] + +object `patvar is assignable`: + var (i, j) = (42, 27) // no warn nonprivate + j += 1 + println((i, j)) + +object `privy patvar is assignable`: + private var (i, j) = (42, 27) // warn + j += 1 + println((i, j)) + +object `local patvar is assignable`: + def f() = + var (i, j) = (42, 27) // warn + j += 1 + println((i, j)) + +object `mutable patvar in for`: + def f(xs: List[Int]) = + for x <- xs; y = x + 1 if y > 10 yield + var z :: Nil = y :: Nil: @unchecked // warn + z + 10 -// todo : This should *NOT* pass in the future -// val c = for { -// case Some(x) <- Option(Option(1)) -// } println(s"hello world") \ No newline at end of file +class `unset var requires -Wunused`: + private var i = 0 // no warn as we didn't ask for it + def f = println(i) diff --git a/tests/warn/i15503e.scala b/tests/warn/i15503e.scala index 46d73a4945cd..2fafec339ac1 100644 --- a/tests/warn/i15503e.scala +++ b/tests/warn/i15503e.scala @@ -1,4 +1,6 @@ -//> using options -Wunused:explicits +//> using options -Wunused:explicits + +import annotation.* object Foo { /* This goes around the "trivial method" detection */ @@ -31,16 +33,17 @@ package scala3main: package foo.test.lambda.param: val default_val = 1 val a = (i: Int) => i // OK - val b = (i: Int) => default_val // OK + val b = (i: Int) => default_val // warn val c = (_: Int) => default_val // OK package foo.test.trivial: /* A twisted test from Scala 2 */ - class C { + class C(val value: Int) { def answer: 42 = 42 object X private def g0(x: Int) = ??? // OK private def f0(x: Int) = () // OK + private def f00(x: Int) = {} // OK private def f1(x: Int) = throw new RuntimeException // OK private def f2(x: Int) = 42 // OK private def f3(x: Int): Option[Int] = None // OK @@ -50,13 +53,16 @@ package foo.test.trivial: private def f7(x: Int) = Y // OK private def f8(x: Int): List[C] = Nil // OK private def f9(x: Int): List[Int] = List(1,2,3,4) // warn - private def foo:Int = 32 // OK + private def foo: Int = 32 // OK private def f77(x: Int) = foo // warn + private def self(x: Int): C = this // no warn + private def unwrap(x: Int): Int = value // no warn } object Y package foo.test.i16955: - class S(var r: String) // OK + class S(var rrr: String) // OK + class T(rrr: String) // warn package foo.test.i16865: trait Foo: @@ -64,7 +70,26 @@ package foo.test.i16865: trait Bar extends Foo object Ex extends Bar: - def fn(a: Int, b: Int): Int = b + 3 // OK + def fn(a: Int, b: Int): Int = b + 3 // warn object Ex2 extends Bar: - override def fn(a: Int, b: Int): Int = b + 3 // OK \ No newline at end of file + override def fn(a: Int, b: Int): Int = b + 3 // warn + +final class alpha(externalName: String) extends StaticAnnotation // no warn annotation arg + +object Unimplemented: + import compiletime.* + inline def f(inline x: Int | Double): Unit = error("unimplemented") // no warn param of trivial method + +def `trivially wrapped`(x: String): String ?=> String = "hello, world" // no warn param of trivial method + +object UnwrapTyped: + import compiletime.error + inline def requireConst(inline x: Boolean | Byte | Short | Int | Long | Float | Double | Char | String): Unit = + error("Compiler bug: `requireConst` was not evaluated by the compiler") + + transparent inline def codeOf(arg: Any): String = + error("Compiler bug: `codeOf` was not evaluated by the compiler") + +object `default usage`: + def f(i: Int)(j: Int = i * 2) = j // warn I guess diff --git a/tests/warn/i15503f.scala b/tests/warn/i15503f.scala index ccf0b7e74065..0550f82d9398 100644 --- a/tests/warn/i15503f.scala +++ b/tests/warn/i15503f.scala @@ -6,9 +6,49 @@ val default_int = 1 object Xd { private def f1(a: Int) = a // OK private def f2(a: Int) = 1 // OK - private def f3(a: Int)(using Int) = a // OK - private def f4(a: Int)(using Int) = default_int // OK + private def f3(a: Int)(using Int) = a // warn + private def f4(a: Int)(using Int) = default_int // warn private def f6(a: Int)(using Int) = summon[Int] // OK private def f7(a: Int)(using Int) = summon[Int] + a // OK private def f8(a: Int)(using foo: Int) = a // warn + private def f9(a: Int)(using Int) = ??? // OK trivial + private def g1(a: Int)(implicit foo: Int) = a // warn } + +trait T +object T: + def hole(using T) = () + +class C(using T) // warn + +class D(using T): + def t = T.hole // nowarn + +object Example: + import scala.quoted.* + given OptionFromExpr[T](using Type[T], FromExpr[T]): FromExpr[Option[T]] with + def unapply(x: Expr[Option[T]])(using Quotes) = x match + case '{ Option[T](${Expr(y)}) } => Some(Option(y)) + case '{ None } => Some(None) + case '{ ${Expr(opt)} : Some[T] } => Some(opt) + case _ => None + +object ExampleWithoutWith: + import scala.quoted.* + given [T] => (Type[T], FromExpr[T]) => FromExpr[Option[T]]: + def unapply(x: Expr[Option[T]])(using Quotes) = x match + case '{ Option[T](${Expr(y)}) } => Some(Option(y)) + case '{ None } => Some(None) + case '{ ${Expr(opt)} : Some[T] } => Some(opt) + case _ => None + +//absolving names on matches of quote trees requires consulting non-abstract types in QuotesImpl +object Unmatched: + import scala.quoted.* + def transform[T](e: Expr[T])(using Quotes): Expr[T] = + import quotes.reflect.* + def f(tree: Tree) = + tree match + case Ident(name) => + case _ => + e diff --git a/tests/warn/i15503g.scala b/tests/warn/i15503g.scala index fbd9f3c1352c..cfbfcdb04d1e 100644 --- a/tests/warn/i15503g.scala +++ b/tests/warn/i15503g.scala @@ -6,8 +6,8 @@ object Foo { private def f1(a: Int) = a // OK private def f2(a: Int) = default_int // warn - private def f3(a: Int)(using Int) = a // OK - private def f4(a: Int)(using Int) = default_int // warn + private def f3(a: Int)(using Int) = a // warn + private def f4(a: Int)(using Int) = default_int // warn // warn private def f6(a: Int)(using Int) = summon[Int] // warn private def f7(a: Int)(using Int) = summon[Int] + a // OK /* --- Trivial method check --- */ @@ -20,4 +20,5 @@ package foo.test.i17101: extension[A] (x: Test[A]) { // OK def value: A = x def causesIssue: Unit = println("oh no") - } \ No newline at end of file + def isAnIssue(y: A): Boolean = x == x // warn + } diff --git a/tests/warn/i15503h.scala b/tests/warn/i15503h.scala index 854693981488..a2bf47c843dd 100644 --- a/tests/warn/i15503h.scala +++ b/tests/warn/i15503h.scala @@ -1,4 +1,4 @@ -//> using options -Wunused:linted +//> using options -Wunused:linted import collection.mutable.Set // warn @@ -7,7 +7,7 @@ class A { val b = 2 // OK private def c = 2 // warn - def d(using x:Int): Int = b // ok + def d(using x: Int): Int = b // warn def e(x: Int) = 1 // OK def f = val x = 1 // warn @@ -15,6 +15,6 @@ class A { 3 def g(x: Int): Int = x match - case x:1 => 0 // OK + case x: 1 => 0 // OK case _ => 1 -} \ No newline at end of file +} diff --git a/tests/warn/i15503i.scala b/tests/warn/i15503i.scala index b7981e0e4206..89ff382eb68c 100644 --- a/tests/warn/i15503i.scala +++ b/tests/warn/i15503i.scala @@ -1,4 +1,4 @@ -//> using options -Wunused:all +//> using options -Wunused:all -Ystop-after:checkUnusedPostInlining import collection.mutable.{Map => MutMap} // warn import collection.mutable.Set // warn @@ -17,10 +17,12 @@ class A { private def c2 = 2 // OK def c3 = c2 - def d1(using x:Int): Int = default_int // ok - def d2(using x:Int): Int = x // OK + def d1(using x: Int): Int = default_int // warn param + def d2(using x: Int): Int = x // OK + def d3(using Int): Int = summon[Int] // OK + def d4(using Int): Int = default_int // warn - def e1(x: Int) = default_int // ok + def e1(x: Int) = default_int // warn param def e2(x: Int) = x // OK def f = val x = 1 // warn @@ -29,11 +31,15 @@ class A { def g = 4 // OK y + g - // todo : uncomment once patvars is fixed - // def g(x: Int): Int = x match - // case x:1 => 0 // ?error - // case x:2 => x // ?OK - // case _ => 1 // ?OK + def g(x: Int): Int = x match + case x: 1 => 0 // no warn same name as selector (for shadowing or unused) + case x: 2 => x // OK + case _ => 1 // OK + + def h(x: Int): Int = x match + case y: 1 => 0 // warn unused despite trivial type and RHS + case y: 2 => y // OK + case _ => 1 // OK } /* ---- CHECK scala.annotation.unused ---- */ @@ -44,7 +50,7 @@ package foo.test.scala.annotation: val default_int = 12 def a1(a: Int) = a // OK - def a2(a: Int) = default_int // ok + def a2(a: Int) = default_int // warn def a3(@unused a: Int) = default_int //OK @@ -82,8 +88,8 @@ package foo.test.i16678: def run = println(foo(number => number.toString, value = 5)) // OK println(foo(number => "", value = 5)) // warn - println(foo(func = number => "", value = 5)) // warn println(foo(func = number => number.toString, value = 5)) // OK + println(foo(func = number => "", value = 5)) // warn println(foo(func = _.toString, value = 5)) // OK package foo.test.possibleclasses: @@ -91,7 +97,7 @@ package foo.test.possibleclasses: k: Int, // OK private val y: Int // OK /* Kept as it can be taken from pattern */ )( - s: Int, + s: Int, // warn val t: Int, // OK private val z: Int // warn ) @@ -130,22 +136,22 @@ package foo.test.possibleclasses: package foo.test.possibleclasses.withvar: case class AllCaseClass( k: Int, // OK - private var y: Int // OK /* Kept as it can be taken from pattern */ + private var y: Int // warn unset )( - s: Int, - var t: Int, // OK - private var z: Int // warn + s: Int, // warn + var ttt: Int, // OK + private var zzz: Int // warn ) case class AllCaseUsed( k: Int, // OK - private var y: Int // OK + private var y: Int // warn unset )( s: Int, // OK - var t: Int, // OK global scope can be set somewhere else - private var z: Int // warn not set + var tt: Int, // OK global scope can be set somewhere else + private var zz: Int // warn not set ) { - def a = k + y + s + t + z + def a = k + y + s + tt + zz } class AllClass( @@ -199,14 +205,14 @@ package foo.test.i16877: package foo.test.i16926: def hello(): Unit = for { - i <- (0 to 10).toList + i <- (0 to 10).toList // warn patvar (a, b) = "hello" -> "world" // OK } yield println(s"$a $b") package foo.test.i16925: def hello = for { - i <- 1 to 2 if true + i <- 1 to 2 if true // OK _ = println(i) // OK } yield () @@ -247,7 +253,7 @@ package foo.test.i16679a: import scala.deriving.Mirror object CaseClassByStringName: inline final def derived[A](using inline A: Mirror.Of[A]): CaseClassByStringName[A] = - new CaseClassByStringName[A]: // warn + new CaseClassByStringName[A]: def name: String = A.toString object secondPackage: @@ -263,7 +269,7 @@ package foo.test.i16679b: object CaseClassName: import scala.deriving.Mirror inline final def derived[A](using inline A: Mirror.Of[A]): CaseClassName[A] = - new CaseClassName[A]: // warn + new CaseClassName[A]: def name: String = A.toString object Foo: @@ -279,7 +285,7 @@ package foo.test.i17156: package a: trait Foo[A] object Foo: - inline def derived[T]: Foo[T] = new Foo{} // warn + inline def derived[T]: Foo[T] = new Foo {} package b: import a.Foo @@ -313,3 +319,52 @@ package foo.test.i17117: val test = t1.test } } + +// manual testing of cached look-ups +package deeply: + object Deep: + def f(): Unit = + def g(): Unit = + def h(): Unit = + println(Deep) + println(Deep) + println(Deep) + h() + g() + override def toString = "man, that is deep!" +/* result cache saves before context traversal and import/member look-up +CHK object Deep +recur * 10 = context depth is 10 between reference and definition +CHK method println +recur = was 19 at predef where max root is 21 +CHK object Deep +recur = cached result +CHK method println +recur +CHK object Deep +recur +*/ + +package constructors: + class C private (i: Int): // warn param + def this() = this(27) + private def this(s: String) = this(s.toInt) // warn ctor + def c = new C(42) + private def f(i: Int) = i // warn overloaded member + private def f(s: String) = s + def g = f("hello") // use one of overloaded member + + class D private (i: Int): + private def this() = this(42) // no warn used by companion + def d = i + object D: + def apply(): D = new D() + +package reversed: // reverse-engineered + class C: + def c: scala.Int = 42 // Int marked used; lint does not look up .scala + class D: + def d: Int = 27 // Int is found in root import scala.* + class E: + import scala.* // no warn because root import (which is cached! by previous lookup) is lower precedence + def e: Int = 27 diff --git a/tests/warn/i15503k.scala b/tests/warn/i15503k.scala new file mode 100644 index 000000000000..8148de44c588 --- /dev/null +++ b/tests/warn/i15503k.scala @@ -0,0 +1,43 @@ + +//> using options -Wunused:imports + +import scala.compiletime.ops.int.* // no warn + +object TupleOps: + /** Type of the element at position N in the tuple X */ + type Elem[X <: Tuple, N <: Int] = X match { + case x *: xs => + N match { + case 0 => x + case S[n1] => Elem[xs, n1] + } + } + + /** Literal constant Int size of a tuple */ + type Size[X <: Tuple] <: Int = X match { + case EmptyTuple => 0 + case x *: xs => S[Size[xs]] + } + +object Summoner: + transparent inline def summoner[T](using x: T): x.type = x + +object `Summoner's Tale`: + import compiletime.summonFrom // no warn + inline def valueOf[T]: T = summonFrom: // implicit match + case ev: ValueOf[T] => ev.value + import Summoner.* // no warn + def f[T](using T): T = summoner[T] // Inlined + +class C: + private def m: Int = 42 // no warn +object C: + class D: + private val c: C = C() // no warn + export c.m // no work to do, expanded member is non-private and uses the select expr + +object UsefulTypes: + trait T +object TypeUser: + import UsefulTypes.* + def f(x: => T) = x diff --git a/tests/warn/i15503kb/power.scala b/tests/warn/i15503kb/power.scala new file mode 100644 index 000000000000..f7e5ccce6d58 --- /dev/null +++ b/tests/warn/i15503kb/power.scala @@ -0,0 +1,14 @@ + +object Power: + import scala.math.pow as power + import scala.quoted.* + inline def powerMacro(x: Double, inline n: Int): Double = ${ powerCode('x, 'n) } + def powerCode(x: Expr[Double], n: Expr[Int])(using Quotes): Expr[Double] = + n match + case Expr(m) => unrolledPowerCode(x, m) + case _ => '{ power($x, $n.toDouble) } + def unrolledPowerCode(x: Expr[Double], n: Int)(using Quotes): Expr[Double] = + n match + case 0 => '{ 1.0 } + case 1 => x + case _ => '{ $x * ${ unrolledPowerCode(x, n - 1) } } diff --git a/tests/warn/i15503kb/square.scala b/tests/warn/i15503kb/square.scala new file mode 100644 index 000000000000..2a5f76e9be83 --- /dev/null +++ b/tests/warn/i15503kb/square.scala @@ -0,0 +1,5 @@ +//> using options -Werror -Wunused:all + +object PowerUser: + import Power.* + def square(x: Double): Double = powerMacro(x, 2) diff --git a/tests/pos/i15967.scala b/tests/warn/i15967.scala similarity index 100% rename from tests/pos/i15967.scala rename to tests/warn/i15967.scala diff --git a/tests/warn/i16639a.scala b/tests/warn/i16639a.scala index 9fe4efe57d7b..ca7798297aea 100644 --- a/tests/warn/i16639a.scala +++ b/tests/warn/i16639a.scala @@ -1,7 +1,7 @@ //> using options -Wunused:all -source:3.3 class Bippy(a: Int, b: Int) { - private def this(c: Int) = this(c, c) + private def this(c: Int) = this(c, c) // warn private def boop(x: Int) = x+a+b // warn private def bippy(x: Int): Int = bippy(x) // warn TODO: could warn final private val MILLIS1 = 2000 // warn no warn, /Dotty:Warn @@ -24,13 +24,13 @@ class B3(msg0: String) extends A("msg") // warn /Dotty: unused explicit paramete trait Bing trait Accessors { - private var v1: Int = 0 // warn warn - private var v2: Int = 0 // warn warn, never set - private var v3: Int = 0 + private var v1: Int = 0 // warn + private var v2: Int = 0 // warn, never set + private var v3: Int = 0 // warn, never got private var v4: Int = 0 // no warn - private[this] var v5 = 0 // warn warn, never set - private[this] var v6 = 0 + private[this] var v5 = 0 // warn, never set + private[this] var v6 = 0 // warn, never got private[this] var v7 = 0 // no warn def bippy(): Int = { @@ -43,13 +43,13 @@ trait Accessors { } class StableAccessors { - private var s1: Int = 0 // warn warn - private var s2: Int = 0 // warn warn, never set - private var s3: Int = 0 + private var s1: Int = 0 // warn + private var s2: Int = 0 // warn, never set + private var s3: Int = 0 // warn, never got private var s4: Int = 0 // no warn - private[this] var s5 = 0 // warn warn, never set - private[this] var s6 = 0 // no warn, limitation /Dotty: Why limitation ? + private[this] var s5 = 0 // warn, never set + private[this] var s6 = 0 // warn, never got private[this] var s7 = 0 // no warn def bippy(): Int = { @@ -62,7 +62,7 @@ class StableAccessors { } trait DefaultArgs { - private def bippy(x1: Int, x2: Int = 10, x3: Int = 15): Int = x1 + x2 + x3 // no more warn warn since #17061 + private def bippy(x1: Int, x2: Int = 10, x3: Int = 15): Int = x1 + x2 + x3 // warn // warn def boppy() = bippy(5, 100, 200) } @@ -91,7 +91,7 @@ trait Locals { } object Types { - private object Dongo { def f = this } // no more warn since #17061 + private object Dongo { def f = this } // warn private class Bar1 // warn warn private class Bar2 // no warn private type Alias1 = String // warn warn @@ -101,7 +101,7 @@ object Types { def f(x: Alias2) = x.length def l1() = { - object HiObject { def f = this } // no more warn since #17061 + object HiObject { def f = this } // warn class Hi { // warn warn def f1: Hi = new Hi def f2(x: Hi) = x @@ -124,9 +124,9 @@ trait Underwarn { } class OtherNames { - private def x_=(i: Int): Unit = () // no more warn since #17061 - private def x: Int = 42 // warn Dotty triggers unused private member : To investigate - private def y_=(i: Int): Unit = () // // no more warn since #17061 + private def x_=(i: Int): Unit = () // warn + private def x: Int = 42 // warn + private def y_=(i: Int): Unit = () // warn private def y: Int = 42 def f = y @@ -145,7 +145,7 @@ trait Forever { val t = Option((17, 42)) for { ns <- t - (i, j) = ns // no warn + (i, j) = ns // warn // warn -Wunused:patvars is in -Wunused:all } yield 42 // val emitted only if needed, hence nothing unused } } @@ -158,14 +158,14 @@ trait CaseyKasem { def f = 42 match { case x if x < 25 => "no warn" case y if toString.nonEmpty => "no warn" + y - case z => "warn" + case z => "warn" // warn patvar } } trait CaseyAtTheBat { def f = Option(42) match { case Some(x) if x < 25 => "no warn" - case Some(y @ _) if toString.nonEmpty => "no warn" - case Some(z) => "warn" + case Some(y @ _) if toString.nonEmpty => "no warn" // warn todo whether to use name @ _ to suppress + case Some(z) => "warn" // warn patvar case None => "no warn" } } @@ -173,7 +173,7 @@ trait CaseyAtTheBat { class `not even using companion privates` object `not even using companion privates` { - private implicit class `for your eyes only`(i: Int) { // no more warn since #17061 + private implicit class `for your eyes only`(i: Int) { // warn def f = i } } @@ -202,4 +202,4 @@ trait `short comings` { val x = 42 // warn /Dotty only triggers in dotty 17 } -} \ No newline at end of file +} diff --git a/tests/pos/i17230.min1.scala b/tests/warn/i17230.min1.scala similarity index 100% rename from tests/pos/i17230.min1.scala rename to tests/warn/i17230.min1.scala diff --git a/tests/pos/i17230.orig.scala b/tests/warn/i17230.orig.scala similarity index 100% rename from tests/pos/i17230.orig.scala rename to tests/warn/i17230.orig.scala diff --git a/tests/pos/i17314.scala b/tests/warn/i17314.scala similarity index 84% rename from tests/pos/i17314.scala rename to tests/warn/i17314.scala index 8ece4a3bd7ac..cff90d843c38 100644 --- a/tests/pos/i17314.scala +++ b/tests/warn/i17314.scala @@ -1,4 +1,4 @@ -//> using options -Xfatal-warnings -Wunused:all -deprecation -feature +//> using options -Wunused:all -deprecation -feature import java.net.URI @@ -10,9 +10,7 @@ object circelike { type Configuration trait ConfiguredCodec[T] object ConfiguredCodec: - inline final def derived[A](using conf: Configuration)(using - inline mirror: Mirror.Of[A] - ): ConfiguredCodec[A] = + inline final def derived[A](using conf: Configuration)(using inline mirror: Mirror.Of[A]): ConfiguredCodec[A] = // warn // warn class InlinedConfiguredCodec extends ConfiguredCodec[A]: val codec = summonInline[Codec[URI]] // simplification new InlinedConfiguredCodec diff --git a/tests/pos/i17314a.scala b/tests/warn/i17314a.scala similarity index 70% rename from tests/pos/i17314a.scala rename to tests/warn/i17314a.scala index 4bce56d8bbed..14ae96848d63 100644 --- a/tests/pos/i17314a.scala +++ b/tests/warn/i17314a.scala @@ -1,4 +1,4 @@ -//> using options -Xfatal-warnings -Wunused:all -deprecation -feature +//> using options -Werror -Wunused:all -deprecation -feature package foo: class Foo[T] diff --git a/tests/warn/i17314b.scala b/tests/warn/i17314b.scala index e1500028ca93..ad4c8f1e4a31 100644 --- a/tests/warn/i17314b.scala +++ b/tests/warn/i17314b.scala @@ -1,4 +1,4 @@ -//> using options -Wunused:all +//> using options -Wunused:all package foo: class Foo[T] diff --git a/tests/warn/i17318.scala b/tests/warn/i17318.scala new file mode 100644 index 000000000000..d242c96484a7 --- /dev/null +++ b/tests/warn/i17318.scala @@ -0,0 +1,33 @@ + +//> using options -Werror -Wunused:all + +object events { + final val PollOut = 0x002 + transparent inline def POLLIN = 0x001 +} + +def withShort(v: Short): Unit = ??? +def withInt(v: Int): Unit = ??? + +def usage() = + import events.POLLIN // reports unused + def v: Short = POLLIN + println(v) + +def usage2() = + import events.POLLIN // reports unused + withShort(POLLIN) + +def usage3() = + import events.POLLIN // does not report unused + withInt(POLLIN) + +def usage4() = + import events.POLLIN // reports unused + withShort(POLLIN) + +def value = 42 +def withDouble(v: Double): Unit = ??? +def usage5() = withDouble(value) +def usage6() = withShort(events.POLLIN) +def usage7() = withShort(events.PollOut) diff --git a/tests/warn/i17371.scala b/tests/warn/i17371.scala new file mode 100644 index 000000000000..f9be76bfed07 --- /dev/null +++ b/tests/warn/i17371.scala @@ -0,0 +1,39 @@ +//> using options -Wunused:all + +class A +class B + +def Test() = + val ordA: Ordering[A] = ??? + val ordB: Ordering[B] = ??? + val a: A = ??? + val b: B = ??? + + import ordA.given + val _ = a > a + + import ordB.given + val _ = b < b + +// unminimized OP +trait Circular[T] extends Ordering[T] +trait Turns[C: Circular, T] extends Ordering[T]: // warn Circular is not a marker interface + extension (turns: T) def extract: C + +def f[K, T](start: T, end: T)(using circular: Circular[K], turns: Turns[K, T]): Boolean = + import turns.given + if start > end then throw new IllegalArgumentException("start must be <= end") + + import circular.given + start.extract < end.extract + +// -Wunused:implicits warns for unused implicit evidence unless it is an empty interface (only universal members). +// scala 2 also offers -Wunused:synthetics for whether to warn for synthetic implicit params. +object ContextBounds: + class C[A: Ordered](a: A): // warn + def f = a + + trait T[A] + + class D[A: T](a: A): // no warn + def f = a diff --git a/tests/warn/i17667.scala b/tests/warn/i17667.scala new file mode 100644 index 000000000000..cc3f6bfc8472 --- /dev/null +++ b/tests/warn/i17667.scala @@ -0,0 +1,10 @@ + +//> using options -Wunused:imports + +object MyImplicits: + extension (a: Int) def print: Unit = println(s"Hello, I am $a") + +import MyImplicits.print //Global import of extension +object Foo: + def printInt(a: Int): Unit = a.print + import MyImplicits.* // warn //Local import of extension diff --git a/tests/warn/i17667b.scala b/tests/warn/i17667b.scala new file mode 100644 index 000000000000..ba8fc7219945 --- /dev/null +++ b/tests/warn/i17667b.scala @@ -0,0 +1,22 @@ + +//> using options -Wunused:all + +import scala.util.Try +import scala.concurrent.* // warn +import scala.collection.Set +class C { + def ss[A](using Set[A]) = println() // warn + private def f = Try(42).get + private def z: Int = // warn + Try(27 + z).get + def g = f + f + def k = + val i = g + g + val j = i + 2 // warn + i + 1 + def c = C() + import scala.util.Try // warn +} +class D { + def d = C().g +} diff --git a/tests/warn/i17753.scala b/tests/warn/i17753.scala new file mode 100644 index 000000000000..66e4fdb8727b --- /dev/null +++ b/tests/warn/i17753.scala @@ -0,0 +1,10 @@ +//> using options -Wunused:all + +class PartiallyApplied[A] { + transparent inline def func[B](): Nothing = ??? +} + +def call[A] = new PartiallyApplied[A] + +def good = call[Int].func[String]() // no warn inline proxy +def bad = { call[Int].func[String]() } // no warn inline proxy diff --git a/tests/warn/i18313.scala b/tests/warn/i18313.scala new file mode 100644 index 000000000000..44b005b313e4 --- /dev/null +++ b/tests/warn/i18313.scala @@ -0,0 +1,14 @@ +//> using options -Werror -Wunused:imports + +import scala.deriving.Mirror + +case class Test(i: Int, d: Double) +case class Decoder(d: Product => Test) + +// OK, no warning returned +//val ok = Decoder(summon[Mirror.Of[Test]].fromProduct) +// +// returns warning: +// [warn] unused import +// [warn] import scala.deriving.Mirror +val d = Decoder(d = summon[Mirror.Of[Test]].fromProduct) // no warn diff --git a/tests/warn/i18366.scala b/tests/warn/i18366.scala new file mode 100644 index 000000000000..b6385b5bbb59 --- /dev/null +++ b/tests/warn/i18366.scala @@ -0,0 +1,19 @@ +//> using options -Werror -Wunused:all + +trait Builder { + def foo(): Unit +} + +def `i18366` = + val builder: Builder = ??? + import builder.{foo => bar} + bar() + +import java.io.DataOutputStream + +val buffer: DataOutputStream = ??? + +import buffer.{write => put} + +def `i17315` = + put(0: Byte) diff --git a/tests/warn/i18564.scala b/tests/warn/i18564.scala new file mode 100644 index 000000000000..3da41265015c --- /dev/null +++ b/tests/warn/i18564.scala @@ -0,0 +1,39 @@ + +//> using option -Wunused:imports + +import scala.compiletime.* +import scala.deriving.* + +trait Foo + +trait HasFoo[A]: + /** true if A contains a Foo */ + val hasFoo: Boolean + +// given instances that need to be imported to be in scope +object HasFooInstances: + given defaultHasFoo[A]: HasFoo[A] with + val hasFoo: Boolean = false + given HasFoo[Foo] with + val hasFoo: Boolean = true + +object HasFooDeriving: + + inline private def tupleHasFoo[T <: Tuple]: Boolean = + inline erasedValue[T] match + case _: EmptyTuple => false + case _: (t *: ts) => summonInline[HasFoo[t]].hasFoo || tupleHasFoo[ts] + + inline def deriveHasFoo[T](using p: Mirror.ProductOf[T]): HasFoo[T] = + // falsely reported as unused even though it has influence on this code + import HasFooInstances.given // no warn at inline method + val pHasFoo = tupleHasFoo[p.MirroredElemTypes] + new HasFoo[T]: // warn New anonymous class definition will be duplicated at each inline site + val hasFoo: Boolean = pHasFoo + +/* the import is used upon inline elaboration +object Test: + import HasFooDeriving.* + case class C(x: Foo, y: Int) + def f: HasFoo[C] = deriveHasFoo[C] +*/ diff --git a/tests/warn/i19252.scala b/tests/warn/i19252.scala new file mode 100644 index 000000000000..42ca99208299 --- /dev/null +++ b/tests/warn/i19252.scala @@ -0,0 +1,13 @@ +//> using options -Werror -Wunused:all +object Deps: + trait D1 + object D2 +end Deps + +object Bug: + import Deps.D1 // no warn + + class Cl(d1: D1): + import Deps.* + def f = (d1, D2) +end Bug diff --git a/tests/warn/i19657-mega.scala b/tests/warn/i19657-mega.scala new file mode 100644 index 000000000000..07411ee73fb1 --- /dev/null +++ b/tests/warn/i19657-mega.scala @@ -0,0 +1,4 @@ +//> using options -Wshadow:type-parameter-shadow -Wunused:all + +class F[X, M[N[X]]]: // warn + private def x[X] = toString // warn // warn diff --git a/tests/warn/i19657.scala b/tests/warn/i19657.scala new file mode 100644 index 000000000000..2caa1c832abe --- /dev/null +++ b/tests/warn/i19657.scala @@ -0,0 +1,117 @@ +//> using options -Wunused:imports -Ystop-after:checkUnusedPostInlining + +trait Schema[A] + +case class Foo() +case class Bar() + +trait SchemaGenerator[A] { + given Schema[A] = new Schema[A]{} +} + +object FooCodec extends SchemaGenerator[Foo] +object BarCodec extends SchemaGenerator[Bar] + +def summonSchemas(using Schema[Foo], Schema[Bar]) = () + +def summonSchema(using Schema[Foo]) = () + +def `i19657 check prefix to pick selector`: Unit = + import FooCodec.given + import BarCodec.given + summonSchemas + +def `i19657 regression test`: Unit = + import FooCodec.given + import BarCodec.given // warn + summonSchema + +def `i19657 check prefix to pick specific selector`: Unit = + import FooCodec.given_Schema_A + import BarCodec.given_Schema_A + summonSchemas + +def `same symbol different names`: Unit = + import FooCodec.given_Schema_A + import FooCodec.given_Schema_A as AThing + summonSchema(using given_Schema_A) + summonSchema(using AThing) + +package i17156: + package a: + trait Foo[A] + object Foo: + class Food[A] extends Foo[A] + inline def derived[T]: Foo[T] = Food() + + package b: + import a.Foo + type Xd[A] = Foo[A] + + package c: + import b.Xd + trait Z derives Xd // checks if dealiased import is prefix a.Foo + class Bar extends Xd[Int] // checks if import qual b is prefix of b.Xd + +object Coll: + class C: + type HM[K, V] = scala.collection.mutable.HashMap[K, V] +object CC extends Coll.C +import CC.* + +def `param type is imported`(map: HM[String, String]): Unit = println(map("hello, world")) + +object Constants: + final val i = 42 + def extra = 3 +def `old-style constants are usages`: Unit = + object Local: + final val j = 27 + import Constants.i + println(i + Local.j) + +object Constantinople: + val k = 42 +class `scope of super`: + import Constants.i // was bad warn + class C(x: Int): + def y = x + class D(j: Int) extends C(i + j): + import Constants.* // does not resolve i in C(i) and does not shadow named import + def m = i // actually picks the higher-precedence import + def f = + import Constantinople.* + class E(e: Int) extends C(i + k): + def g = e + y + k + 1 + E(0).g + def consume = extra // use the wildcard import from Constants + +import scala.annotation.meta.* +object Alias { + type A = Deprecated @param +} + +// avoid reporting on runtime (nothing to do with transparent inline) +import scala.runtime.EnumValue + +trait Lime + +enum Color(val rgb: Int): + case Red extends Color(0xFF0000) with EnumValue + case Green extends Color(0x00FF00) with Lime + case Blue extends Color(0x0000FF) + +object prefixes: + class C: + object N: + type U + object Test: + val c: C = ??? + def k2: c.N.U = ??? + import c.N.* + def k3: U = ??? // TypeTree if not a select + object Alt: + val c: C = ??? + import c.N + def k4: N.U = ??? +end prefixes diff --git a/tests/warn/i20520.scala b/tests/warn/i20520.scala new file mode 100644 index 000000000000..e09d16c27af2 --- /dev/null +++ b/tests/warn/i20520.scala @@ -0,0 +1,11 @@ + +//> using options -Wunused:all + +@main def run = + val veryUnusedVariable: Int = value // warn local + +package i20520: + private def veryUnusedMethod(x: Int): Unit = println() // warn param + private val veryUnusedVariableToplevel: Unit = println() // package members are accessible under separate compilation + +def value = 42 diff --git a/tests/pos/i20860.scala b/tests/warn/i20860.scala similarity index 74% rename from tests/pos/i20860.scala rename to tests/warn/i20860.scala index 1e1ddea11b75..b318d861fce0 100644 --- a/tests/pos/i20860.scala +++ b/tests/warn/i20860.scala @@ -1,3 +1,5 @@ +//> using options -Werror -Wunused:imports + def `i20860 use result to check selector bound`: Unit = import Ordering.Implicits.given Ordering[?] summon[Ordering[Seq[Int]]] diff --git a/tests/warn/i20951.scala b/tests/warn/i20951.scala new file mode 100644 index 000000000000..0ca82e1b8d66 --- /dev/null +++ b/tests/warn/i20951.scala @@ -0,0 +1,7 @@ +//> using options -Wunused:all +object Foo { + val dummy = 42 + def f(): Unit = Option(1).map((x: Int) => dummy) // warn + def g(): Unit = Option(1).map((x: Int) => ???) // warn + def main(args: Array[String]): Unit = {} +} diff --git a/tests/warn/i21420.scala b/tests/warn/i21420.scala index 0ee4aa3f28f6..65a288c7ae5b 100644 --- a/tests/warn/i21420.scala +++ b/tests/warn/i21420.scala @@ -1,4 +1,4 @@ -//> using options -Wunused:imports +//> using options -Werror -Wunused:imports object decisions4s{ trait HKD @@ -7,7 +7,7 @@ object decisions4s{ object DiagnosticsExample { import decisions4s.HKD - val _ = new HKD {} + case class Input[F[_]]() extends HKD import decisions4s.* - val _ = new DecisionTable {} + val decisionTable: DecisionTable = ??? } diff --git a/tests/warn/i21525.scala b/tests/warn/i21525.scala new file mode 100644 index 000000000000..aa156dc3960e --- /dev/null +++ b/tests/warn/i21525.scala @@ -0,0 +1,20 @@ +//> using options -Werror -Wunused:imports + +import scala.reflect.TypeTest + +trait A { + type B + type C <: B + + given instance: TypeTest[B, C] +} + +def f(a: A, b: a.B): Boolean = { + import a.C + b match { + case _: C => + true + case _ => + false + } +} diff --git a/tests/warn/i21809.scala b/tests/warn/i21809.scala new file mode 100644 index 000000000000..91e7a334b13b --- /dev/null +++ b/tests/warn/i21809.scala @@ -0,0 +1,17 @@ +//> using options -Wunused:imports + +package p { + package q { + import q.* // warn so long as we pass typer + class Test { + //override def toString = new C().toString + " for Test" + def d = D() + } + class D + } +} +package q { + class C { + override def toString = "q.C" + } +} diff --git a/tests/warn/i21917.scala b/tests/warn/i21917.scala new file mode 100644 index 000000000000..cade4e90db3d --- /dev/null +++ b/tests/warn/i21917.scala @@ -0,0 +1,27 @@ +//> using options -Wunused:imports + +import Pet.Owner + +class Dog(owner: Owner) extends Pet(owner) { + import Pet.* // warn although unambiguous (i.e., it was disambiguated) + //import Car.* // ambiguous + + def bark(): String = "bite" + + def this(owner: Owner, goodDog: Boolean) = { + this(owner) + if (goodDog) println(s"$owner's dog is a good boy") + } + + val getOwner: Owner = owner +} + +class Pet(val owner: Owner) + +object Pet { + class Owner +} + +object Car { + class Owner +} diff --git a/tests/warn/i22371.scala b/tests/warn/i22371.scala new file mode 100644 index 000000000000..00f5b66695e0 --- /dev/null +++ b/tests/warn/i22371.scala @@ -0,0 +1,8 @@ +//> using options -Werror -Wunused:all +import scala.compiletime.deferred + +class Context + +trait Foo: + given context: Context = deferred + given () => Context = deferred diff --git a/tests/warn/i3323.scala b/tests/warn/i3323.scala new file mode 100644 index 000000000000..e409134ff0ba --- /dev/null +++ b/tests/warn/i3323.scala @@ -0,0 +1,8 @@ +//> using options -Werror +class Foo { + def foo[A](lss: List[List[A]]): Unit = { + lss match { + case xss: List[List[A]] => // no warn erasure + } + } +} diff --git a/tests/pos/patmat-exhaustive.scala b/tests/warn/patmat-exhaustive.scala similarity index 56% rename from tests/pos/patmat-exhaustive.scala rename to tests/warn/patmat-exhaustive.scala index 9e3cb7d8f615..a8f057664829 100644 --- a/tests/pos/patmat-exhaustive.scala +++ b/tests/warn/patmat-exhaustive.scala @@ -1,4 +1,4 @@ -//> using options -Xfatal-warnings -deprecation -feature +//> using options -Werror -deprecation -feature def foo: Unit = object O: @@ -8,5 +8,5 @@ def foo: Unit = val x: O.A = ??? x match - case x: B => ??? - case x: C => ??? + case _: B => ??? + case _: C => ??? diff --git a/tests/warn/scala2-t11681.scala b/tests/warn/scala2-t11681.scala index ae2187181ceb..5d752777f64c 100644 --- a/tests/warn/scala2-t11681.scala +++ b/tests/warn/scala2-t11681.scala @@ -23,7 +23,7 @@ trait BadAPI extends InterFace { a } override def call(a: Int, - b: String, // OK + b: String, // warn now c: Double): Int = { println(c) a @@ -33,7 +33,7 @@ trait BadAPI extends InterFace { override def equals(other: Any): Boolean = true // OK - def i(implicit s: String) = answer // ok + def i(implicit s: String) = answer // warn now /* def future(x: Int): Int = { @@ -59,10 +59,10 @@ class Revaluing(u: Int) { def f = u } // OK case class CaseyKasem(k: Int) // OK -case class CaseyAtTheBat(k: Int)(s: String) // ok +case class CaseyAtTheBat(k: Int)(s: String) // warn unused s trait Ignorance { - def f(readResolve: Int) = answer // ok + def f(readResolve: Int) = answer // warn now } class Reusing(u: Int) extends Unusing(u) // OK @@ -78,30 +78,30 @@ trait Unimplementation { trait DumbStuff { def f(implicit dummy: DummyImplicit) = answer // ok - def g(dummy: DummyImplicit) = answer // ok + def g(dummy: DummyImplicit) = answer // warn now } trait Proofs { def f[A, B](implicit ev: A =:= B) = answer // ok def g[A, B](implicit ev: A <:< B) = answer // ok - def f2[A, B](ev: A =:= B) = answer // ok - def g2[A, B](ev: A <:< B) = answer // ok + def f2[A, B](ev: A =:= B) = answer // warn now + def g2[A, B](ev: A <:< B) = answer // warn now } trait Anonymous { - def f = (i: Int) => answer // ok + def f = (i: Int) => answer // warn now def f1 = (_: Int) => answer // OK def f2: Int => Int = _ + 1 // OK - def g = for (i <- List(1)) yield answer // ok + def g = for (i <- List(1)) yield answer // no warn (that is a patvar) } trait Context[A] trait Implicits { - def f[A](implicit ctx: Context[A]) = answer // ok - def g[A: Context] = answer // OK + def f[A](implicit ctx: Context[A]) = answer // warn implicit param even though only marker + def g[A: Context] = answer // no warn bound that is marker only } -class Bound[A: Context] // OK +class Bound[A: Context] // no warn bound that is marker only object Answers { def answer: Int = 42 } diff --git a/tests/warn/tuple-exhaustivity.scala b/tests/warn/tuple-exhaustivity.scala new file mode 100644 index 000000000000..9060d112b197 --- /dev/null +++ b/tests/warn/tuple-exhaustivity.scala @@ -0,0 +1,6 @@ +//> using options -Werror -deprecation -feature + +def test(t: Tuple) = + t match + case Tuple() => + case h *: t => diff --git a/tests/warn/unused-can-equal.scala b/tests/warn/unused-can-equal.scala new file mode 100644 index 000000000000..6e38591ccef1 --- /dev/null +++ b/tests/warn/unused-can-equal.scala @@ -0,0 +1,16 @@ + +//> using options -Werror -Wunused:all + +import scala.language.strictEquality + +class Box[T](x: T) derives CanEqual: + def y = x + +def f[A, B](a: A, b: B)(using CanEqual[A, B]) = a == b // no warn + +def g = + import Box.given // no warn + "42".length + +@main def test() = println: + Box(1) == Box(1L) diff --git a/tests/warn/unused-locals.scala b/tests/warn/unused-locals.scala new file mode 100644 index 000000000000..10bf160fb717 --- /dev/null +++ b/tests/warn/unused-locals.scala @@ -0,0 +1,43 @@ +//> using options -Wunused:locals + +class Outer { + class Inner +} + +trait Locals { + def f0 = { + var x = 1 // warn + var y = 2 // no warn + y = 3 + y + y + } + def f1 = { + val a = new Outer // no warn + val b = new Outer // warn + new a.Inner + } + def f2 = { + var x = 100 // warn about it being a var + x + } +} + +object Types { + def l1() = { + object HiObject { def f = this } // warn + class Hi { // warn + def f1: Hi = new Hi + def f2(x: Hi) = x + } + class DingDongDoobie // warn + class Bippy // no warn + type Something = Bippy // no warn + type OtherThing = String // warn + (new Bippy): Something + } +} + +// breakage: local val x$1 in method skolemize is never used +case class SymbolKind(accurate: String, sanitized: String, abbreviation: String) { + def skolemize: SymbolKind = copy(accurate = s"$accurate skolem", abbreviation = s"$abbreviation#SKO") +} diff --git a/tests/warn/unused-params.scala b/tests/warn/unused-params.scala new file mode 100644 index 000000000000..5ef339c942ac --- /dev/null +++ b/tests/warn/unused-params.scala @@ -0,0 +1,159 @@ +//> using options -Wunused:params +// + +import Answers._ + +trait InterFace { + /** Call something. */ + def call(a: Int, b: String, c: Double): Int +} + +trait BadAPI extends InterFace { + def f(a: Int, + b: String, // warn + c: Double): Int = { + println(c) + a + } + @deprecated("no warn in deprecated API", since="yesterday") + def g(a: Int, + b: String, // no warn + c: Double): Int = { + println(c) + a + } + override def call(a: Int, + b: String, // warn + c: Double): Int = { + println(c) + a + } + + def meth(x: Int) = x + + override def equals(other: Any): Boolean = true // no warn + + def i(implicit s: String) = answer // warn + + /* + def future(x: Int): Int = { + val y = 42 + val x = y // maybe option to warn only if shadowed + x + } + */ +} + +// mustn't alter warnings in super +trait PoorClient extends BadAPI { + override def meth(x: Int) = ??? // no warn + override def f(a: Int, b: String, c: Double): Int = a + b.toInt + c.toInt +} + +class Unusing(u: Int) { // warn + def f = ??? +} + +class Valuing(val u: Int) // no warn + +class Revaluing(u: Int) { def f = u } // no warn + +case class CaseyKasem(k: Int) // no warn + +case class CaseyAtTheBat(k: Int)(s: String) // warn + +trait Ignorance { + def f(readResolve: Int) = answer // warn +} + +class Reusing(u: Int) extends Unusing(u) // no warn + +class Main { + def main(args: Array[String]): Unit = println("hello, args") // no warn +} + +trait Unimplementation { + def f(u: Int): Int = ??? // no warn for param in unimplementation +} + +trait DumbStuff { + def f(implicit dummy: DummyImplicit) = answer + def g(dummy: DummyImplicit) = answer // warn +} +trait Proofs { + def f[A, B](implicit ev: A =:= B) = answer + def g[A, B](implicit ev: A <:< B) = answer + def f2[A, B](ev: A =:= B) = answer // warn + def g2[A, B](ev: A <:< B) = answer // warn +} + +trait Anonymous { + def f = (i: Int) => answer // warn + + def f1 = (_: Int) => answer // no warn underscore parameter (a fresh name) + + def f2: Int => Int = _ + 1 // no warn placeholder syntax (a fresh name and synthetic parameter) + + def g = for (i <- List(1)) yield answer // no warn patvar elaborated as map.(i => 42) +} +trait Context[A] { def m(a: A): A = a } +trait Implicits { + def f[A](implicit ctx: Context[A]) = answer // warn + def g[A: Context] = answer // warn + def h[A](using Context[A]) = answer // warn +} +class Bound[A: Context] // warn +object Answers { + def answer: Int = 42 +} + +trait BadMix { self: InterFace => + def f(a: Int, + b: String, // warn + c: Double): Int = { + println(c) + a + } + @deprecated("no warn in deprecated API", since="yesterday") + def g(a: Int, + b: String, // no warn + c: Double): Int = { + println(c) + a + } + override def call(a: Int, + XXXX: String, // warn no longer excused because required by superclass + c: Double): Int = { + println(c) + a + } + + def meth(x: Int) = x + + override def equals(other: Any): Boolean = true // no warn + + def i(implicit s: String) = answer // warn +} + +class Unequal { + override def equals(other: Any) = toString.nonEmpty // warn +} + +class Seriously { + def f(s: Serializable) = toString.nonEmpty // warn explicit param of marker trait +} + +class TryStart(start: String) { + def FINALLY(end: END.type) = start // no warn for DSL taking a singleton +} + +object END + +object Optional: + extension (opt: Option.type) // no warn for extension of module + @annotation.experimental + inline def fromNullable[T](t: T | Null): Option[T] = Option(t).asInstanceOf[Option[T]] + +class Nested { + @annotation.unused private def actuallyNotUsed(fresh: Int, stale: Int) = fresh // no warn if owner is unused +} diff --git a/tests/warn/unused-privates.scala b/tests/warn/unused-privates.scala new file mode 100644 index 000000000000..8864bc16de2b --- /dev/null +++ b/tests/warn/unused-privates.scala @@ -0,0 +1,310 @@ +// +//> using options -deprecation -Wunused:privates,locals +// +class Bippy(a: Int, b: Int) { + private def this(c: Int) = this(c, c) // warn (DO warn, was NO) + private def bippy(x: Int): Int = bippy(x) // warn + private def boop(x: Int) = x+a+b // warn + final private val MILLIS1 = 2000 // warn, scala2: no warn, might have been inlined + final private val MILLIS2: Int = 1000 // warn + final private val HI_COMPANION: Int = 500 // no warn, accessed from companion + def hi() = Bippy.HI_INSTANCE +} +object Bippy { + def hi(x: Bippy) = x.HI_COMPANION + private val HI_INSTANCE: Int = 500 // no warn, accessed from instance + private val HEY_INSTANCE: Int = 1000 // warn + private lazy val BOOL: Boolean = true // warn +} + +class A(val msg: String) +class B1(msg: String) extends A(msg) +class B2(msg0: String) extends A(msg0) +class B3(msg0: String) extends A("msg") + +trait Accessors { + private var v1: Int = 0 // warn + private var v2: Int = 0 // warn, never set + private var v3: Int = 0 // warn, never got + private var v4: Int = 0 // no warn + + private var v5 = 0 // warn, never set + private var v6 = 0 // warn, never got + private var v7 = 0 // no warn + + def bippy(): Int = { + v3 = 3 + v4 = 4 + v6 = 6 + v7 = 7 + v2 + v4 + v5 + v7 + } +} + +class StableAccessors { + private var s1: Int = 0 // warn + private var s2: Int = 0 // warn, never set + private var s3: Int = 0 // warn, never got + private var s4: Int = 0 // no warn + + private var s5 = 0 // warn, never set + private var s6 = 0 // warn, never got + private var s7 = 0 // no warn + + def bippy(): Int = { + s3 = 3 + s4 = 4 + s6 = 6 + s7 = 7 + s2 + s4 + s5 + s7 + } +} + +trait DefaultArgs { + // DO warn about default getters for x2 and x3 + private def bippy(x1: Int, x2: Int = 10, x3: Int = 15): Int = x1 + x2 + x3 // warn // warn + + def boppy() = bippy(5, 100, 200) +} + +/* scala/bug#7707 Both usages warn default arg because using PrivateRyan.apply, not new. +case class PrivateRyan private (ryan: Int = 42) { def f = PrivateRyan() } +object PrivateRyan { def f = PrivateRyan() } +*/ + +class Outer { + class Inner +} + +trait Locals { + def f0 = { + var x = 1 // warn + var y = 2 + y = 3 + y + y + } + def f1 = { + val a = new Outer // no warn + val b = new Outer // warn + new a.Inner + } + def f2 = { + var x = 100 // warn about it being a var + x + } +} + +object Types { + private object Dongo { def f = this } // warn + private class Bar1 // warn + private class Bar2 // no warn + private type Alias1 = String // warn + private type Alias2 = String // no warn + def bippo = (new Bar2).toString + + def f(x: Alias2) = x.length + + def l1() = { + object HiObject { def f = this } // warn + class Hi { // warn + def f1: Hi = new Hi + def f2(x: Hi) = x + } + class DingDongDoobie // warn + class Bippy // no warn + type Something = Bippy // no warn + type OtherThing = String // warn + (new Bippy): Something + } +} + +trait Underwarn { + def f(): Seq[Int] + + def g() = { + val Seq(_, _) = f() // no warn + true + } +} + +class OtherNames { + private def x_=(i: Int): Unit = () // warn + private def x: Int = 42 // warn + private def y_=(i: Int): Unit = () // warn + private def y: Int = 42 + + def f = y +} + +case class C(a: Int, b: String, c: Option[String]) +case class D(a: Int) + +// patvars which used to warn as vals in older scala 2 +trait Boundings { + + def c = C(42, "hello", Some("world")) + def d = D(42) + + def f() = { + val C(x, y, Some(z)) = c: @unchecked // no warn + 17 + } + def g() = { + val C(x @ _, y @ _, Some(z @ _)) = c: @unchecked // no warn + 17 + } + def h() = { + val C(x @ _, y @ _, z @ Some(_)) = c: @unchecked // no warn for z? + 17 + } + + def v() = { + val D(x) = d // no warn + 17 + } + def w() = { + val D(x @ _) = d // no warn + 17 + } + +} + +trait Forever { + def f = { + val t = Option((17, 42)) + for { + ns <- t + (i, j) = ns // no warn + } yield (i + j) + } + def g = { + val t = Option((17, 42)) + for { + ns <- t + (i, j) = ns // no warn + } yield 42 // val emitted only if needed, hence nothing unused + } +} + +trait Ignorance { + private val readResolve = 42 // warn wrong signatured for special members +} + +trait CaseyKasem { + def f = 42 match { + case x if x < 25 => "no warn" + case y if toString.nonEmpty => "no warn" + y + case z => "warn" + } +} +trait CaseyAtTheBat { + def f = Option(42) match { + case Some(x) if x < 25 => "no warn" + case Some(y @ _) if toString.nonEmpty => "no warn" + case Some(z) => "warn" + case None => "no warn" + } +} + +class `not even using companion privates` + +object `not even using companion privates` { + private implicit class `for your eyes only`(i: Int) { // warn + def f = i + } +} + +class `no warn in patmat anonfun isDefinedAt` { + def f(pf: PartialFunction[String, Int]) = pf("42") + def g = f { + case s => s.length // no warn (used to warn case s => true in isDefinedAt) + } +} + +// this is the ordinary case, as AnyRef is an alias of Object +class `nonprivate alias is enclosing` { + class C + type C2 = C + private class D extends C2 // warn +} + +object `classof something` { + private class intrinsically + def f = classOf[intrinsically].toString() +} + +trait `scala 2 short comings` { + def f: Int = { + val x = 42 // warn + 17 + } +} + +class `issue 12600 ignore abstract types` { + type Abs +} + +class `t12992 enclosing def is unused` { + private val n = 42 + @annotation.unused def f() = n + 2 // unused code uses n +} + +class `recursive reference is not a usage` { + private def f(i: Int): Int = // warn + if (i <= 0) i + else f(i-1) + private class P { // warn + def f() = new P() + } +} + +class `absolve serial framework` extends Serializable: + import java.io.{IOException, ObjectInputStream, ObjectOutputStream, ObjectStreamException} + @throws(classOf[IOException]) + private def writeObject(stream: ObjectOutputStream): Unit = () + @throws(classOf[ObjectStreamException]) + private def writeReplace(): Object = ??? + @throws(classOf[ClassNotFoundException]) + @throws(classOf[IOException]) + private def readObject(stream: ObjectInputStream): Unit = () + @throws(classOf[ObjectStreamException]) + private def readObjectNoData(): Unit = () + @throws(classOf[ObjectStreamException]) + private def readResolve(): Object = ??? + +class `absolve ONLY serial framework`: + import java.io.{IOException, ObjectInputStream, ObjectOutputStream, ObjectStreamException} + @throws(classOf[IOException]) + private def writeObject(stream: ObjectOutputStream): Unit = () // warn + @throws(classOf[ObjectStreamException]) + private def writeReplace(): Object = new Object // warn + @throws(classOf[ClassNotFoundException]) + @throws(classOf[IOException]) + private def readObject(stream: ObjectInputStream): Unit = () // warn + @throws(classOf[ObjectStreamException]) + private def readObjectNoData(): Unit = () // warn + @throws(classOf[ObjectStreamException]) + private def readResolve(): Object = new Object // warn + +@throws(classOf[java.io.ObjectStreamException]) +private def readResolve(): Object = ??? // TODO warn +private def print() = println() // TODO warn +private val printed = false // TODO warn + +package locked: + private[locked] def locker(): Unit = () // TODO warn as we cannot distinguish unqualified private at top level + package basement: + private[locked] def shackle(): Unit = () // no warn as it is not top level at boundary + +object `i19998 refinement`: + trait Foo { + type X[a] + } + trait Bar[X[_]] { + private final type SelfX[a] = X[a] // was false positive + val foo: Foo { type X[a] = SelfX[a] } + } + +object `patvar is assignable`: + private var (i, j) = (42, 27) // no warn patvars under -Wunused:privates + println((i, j)) From 0983d9cbb5716ebab345bdb2777133e8eff3d448 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Thu, 10 Apr 2025 17:05:19 +0200 Subject: [PATCH 039/505] Respect prefix when checking if selector selects Use miniphase api instead of traversing. Share a megaphase with CheckShadowing. Perform more expensive checks last. Avoid intermediate collections. Tighten allowance for serialization methods. Don't ignore params of public methods. Show misplaced warn comment, unfulfilled expectations. Warn for unused patvars. Don't warn about canonical names (case class element names). Warn unassigned mutable patvars No transparent inline exclusion. Handle match types. No warn inline proxy. Detect summon inline. Unused import diagnostics have an origin. Original of literal. Typos in build. Handle aliased boolean settings. Resolve imports post inlining. Excuse only empty interfaces as unused bound. Use result of TypeTest. [Cherry-picked c65d45d6a9eb665cf81359a0f0d5d1f1bc716398][modified] From 03327d5dce82c50e3118befb0173778335732b8f Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Wed, 15 Jan 2025 17:41:11 -0800 Subject: [PATCH 040/505] Prefer dotc.util.chaining --- compiler/src/dotty/tools/backend/jvm/ClassfileWriters.scala | 4 ++-- compiler/src/dotty/tools/dotc/config/CliCommand.scala | 2 +- compiler/src/dotty/tools/dotc/config/ScalaSettings.scala | 2 +- compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala | 2 +- compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala | 2 +- compiler/src/dotty/tools/dotc/semanticdb/TypeOps.scala | 2 +- .../dotty/tools/dotc/transform/localopt/FormatChecker.scala | 3 +-- compiler/src/dotty/tools/dotc/util/ReusableInstance.scala | 2 +- compiler/src/dotty/tools/dotc/util/SourceFile.scala | 2 +- compiler/src/dotty/tools/dotc/util/StackTraceOps.scala | 2 +- compiler/src/dotty/tools/repl/ReplCompiler.scala | 2 +- 11 files changed, 12 insertions(+), 13 deletions(-) diff --git a/compiler/src/dotty/tools/backend/jvm/ClassfileWriters.scala b/compiler/src/dotty/tools/backend/jvm/ClassfileWriters.scala index 536ab887a740..5dcafbef750f 100644 --- a/compiler/src/dotty/tools/backend/jvm/ClassfileWriters.scala +++ b/compiler/src/dotty/tools/backend/jvm/ClassfileWriters.scala @@ -12,10 +12,10 @@ import java.util.zip.{CRC32, Deflater, ZipEntry, ZipOutputStream} import dotty.tools.dotc.core.Contexts.* import dotty.tools.dotc.core.Decorators.em +import dotty.tools.dotc.util.chaining.* import dotty.tools.io.{AbstractFile, PlainFile, VirtualFile} import dotty.tools.io.PlainFile.toPlainFile import BTypes.InternalName -import scala.util.chaining._ import dotty.tools.io.JarArchive import scala.language.unsafeNulls @@ -180,7 +180,7 @@ class ClassfileWriters(frontendAccess: PostProcessorFrontendAccess) { // important detail here, even on Windows, Zinc expects the separator within the jar // to be the system default, (even if in the actual jar file the entry always uses '/'). // see https://github.com/sbt/zinc/blob/dcddc1f9cfe542d738582c43f4840e17c053ce81/internal/compiler-bridge/src/main/scala/xsbt/JarUtils.scala#L47 - val pathInJar = + val pathInJar = if File.separatorChar == '/' then relativePath else relativePath.replace('/', File.separatorChar) PlainFile.toPlainFile(Paths.get(s"${file.absolutePath}!$pathInJar")) diff --git a/compiler/src/dotty/tools/dotc/config/CliCommand.scala b/compiler/src/dotty/tools/dotc/config/CliCommand.scala index b76af885765c..5ec51c1b5b0f 100644 --- a/compiler/src/dotty/tools/dotc/config/CliCommand.scala +++ b/compiler/src/dotty/tools/dotc/config/CliCommand.scala @@ -7,7 +7,7 @@ import Settings.* import core.Contexts.* import printing.Highlighting -import scala.util.chaining.given +import dotty.tools.dotc.util.chaining.* import scala.PartialFunction.cond trait CliCommand: diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index b864446f19d5..8dfe72cf85d4 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -12,7 +12,7 @@ import dotty.tools.io.{AbstractFile, Directory, JDK9Reflectors, PlainDirectory} import dotty.tools.backend.jvm.BackendUtils.classfileVersionMap import Setting.ChoiceWithHelp -import scala.util.chaining.* +import dotty.tools.dotc.util.chaining.* import java.util.zip.Deflater diff --git a/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala b/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala index 102572b82bbc..20be33716831 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala @@ -8,9 +8,9 @@ import dotty.tools.dotc.config.Settings.Setting import dotty.tools.dotc.core.Contexts.* import dotty.tools.dotc.interfaces.Diagnostic.{ERROR, INFO, WARNING} import dotty.tools.dotc.util.SourcePosition +import dotty.tools.dotc.util.chaining.* import java.util.{Collections, Optional, List => JList} -import scala.util.chaining.* import core.Decorators.toMessage object Diagnostic: diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala index 73f69dd6f2ad..59697796b76d 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala @@ -24,7 +24,7 @@ import java.io.PrintWriter import scala.collection.mutable import scala.util.hashing.MurmurHash3 -import scala.util.chaining.* +import dotty.tools.dotc.util.chaining.* /** This phase sends a representation of the API of classes to sbt via callbacks. * diff --git a/compiler/src/dotty/tools/dotc/semanticdb/TypeOps.scala b/compiler/src/dotty/tools/dotc/semanticdb/TypeOps.scala index 4293ecd6ca43..2d98535657a2 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/TypeOps.scala @@ -9,13 +9,13 @@ import core.Annotations.Annotation import core.Flags import core.Names.Name import core.StdNames.tpnme -import scala.util.chaining.scalaUtilChainingOps import collection.mutable import dotty.tools.dotc.{semanticdb => s} import Scala3.{FakeSymbol, SemanticSymbol, WildcardTypeSymbol, TypeParamRefSymbol, TermParamRefSymbol, RefinementSymbol} import dotty.tools.dotc.core.Names.Designator +import dotty.tools.dotc.util.chaining.* class TypeOps: import SymbolScopeOps.* diff --git a/compiler/src/dotty/tools/dotc/transform/localopt/FormatChecker.scala b/compiler/src/dotty/tools/dotc/transform/localopt/FormatChecker.scala index 9e40792895c0..4922024b6c35 100644 --- a/compiler/src/dotty/tools/dotc/transform/localopt/FormatChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/localopt/FormatChecker.scala @@ -3,10 +3,8 @@ package transform.localopt import scala.annotation.tailrec import scala.collection.mutable.ListBuffer -import scala.util.chaining.* import scala.util.matching.Regex.Match - import PartialFunction.cond import dotty.tools.dotc.ast.tpd.{Match => _, *} @@ -15,6 +13,7 @@ import dotty.tools.dotc.core.Symbols.* import dotty.tools.dotc.core.Types.* import dotty.tools.dotc.core.Phases.typerPhase import dotty.tools.dotc.util.Spans.Span +import dotty.tools.dotc.util.chaining.* /** Formatter string checker. */ class TypedFormatChecker(partsElems: List[Tree], parts: List[String], args: List[Tree])(using Context): diff --git a/compiler/src/dotty/tools/dotc/util/ReusableInstance.scala b/compiler/src/dotty/tools/dotc/util/ReusableInstance.scala index ec88b5880745..cca7af0d2fa3 100644 --- a/compiler/src/dotty/tools/dotc/util/ReusableInstance.scala +++ b/compiler/src/dotty/tools/dotc/util/ReusableInstance.scala @@ -1,7 +1,7 @@ package dotty.tools.dotc.util import scala.collection.mutable.ArrayBuffer -import scala.util.chaining.* +import dotty.tools.dotc.util.chaining.* /** A wrapper for a list of cached instances of a type `T`. * The wrapper is recursion-reentrant: several instances are kept, so diff --git a/compiler/src/dotty/tools/dotc/util/SourceFile.scala b/compiler/src/dotty/tools/dotc/util/SourceFile.scala index 246255ae3802..939690bb2ee0 100644 --- a/compiler/src/dotty/tools/dotc/util/SourceFile.scala +++ b/compiler/src/dotty/tools/dotc/util/SourceFile.scala @@ -13,7 +13,7 @@ import Chars.* import scala.annotation.internal.sharable import scala.collection.mutable import scala.collection.mutable.ArrayBuffer -import scala.util.chaining.given +import dotty.tools.dotc.util.chaining.* import java.io.File.separator import java.net.URI diff --git a/compiler/src/dotty/tools/dotc/util/StackTraceOps.scala b/compiler/src/dotty/tools/dotc/util/StackTraceOps.scala index f991005f0c43..bd5c031a65e0 100644 --- a/compiler/src/dotty/tools/dotc/util/StackTraceOps.scala +++ b/compiler/src/dotty/tools/dotc/util/StackTraceOps.scala @@ -15,7 +15,7 @@ package dotty.tools.dotc.util import scala.language.unsafeNulls import collection.mutable, mutable.ListBuffer -import scala.util.chaining.given +import dotty.tools.dotc.util.chaining.* import java.lang.System.lineSeparator object StackTraceOps: diff --git a/compiler/src/dotty/tools/repl/ReplCompiler.scala b/compiler/src/dotty/tools/repl/ReplCompiler.scala index 06c81c499e5d..e34bb229a727 100644 --- a/compiler/src/dotty/tools/repl/ReplCompiler.scala +++ b/compiler/src/dotty/tools/repl/ReplCompiler.scala @@ -18,9 +18,9 @@ import dotty.tools.dotc.util.Spans.* import dotty.tools.dotc.util.{ParsedComment, Property, SourceFile} import dotty.tools.dotc.{CompilationUnit, Compiler, Run} import dotty.tools.repl.results.* +import dotty.tools.dotc.util.chaining.* import scala.collection.mutable -import scala.util.chaining.given /** This subclass of `Compiler` is adapted for use in the REPL. * From 054d7401eaf2a4eb351d4767e3fbef691315ed7e Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Thu, 10 Apr 2025 17:07:49 +0200 Subject: [PATCH 041/505] Prefer dotc.util.chaining [Cherry-picked a5d9e25ff2892b19899efa7ad207cd155e87219c][modified] From cdafa86cc28c7398025434688af10784dc614847 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Mon, 27 Jan 2025 08:54:21 -0800 Subject: [PATCH 042/505] Nowarn LazyVals [Cherry-picked 6c2c5c549cc2c08364bffb034bb27de321b5a16f] --- library/src/scala/runtime/LazyVals.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/src/scala/runtime/LazyVals.scala b/library/src/scala/runtime/LazyVals.scala index 33ccea4325a5..f3225a4acbd6 100644 --- a/library/src/scala/runtime/LazyVals.scala +++ b/library/src/scala/runtime/LazyVals.scala @@ -96,13 +96,13 @@ object LazyVals { println(s"CAS($t, $offset, $e, $v, $ord)") val mask = ~(LAZY_VAL_MASK << ord * BITS_PER_LAZY_VAL) val n = (e & mask) | (v.toLong << (ord * BITS_PER_LAZY_VAL)) - unsafe.compareAndSwapLong(t, offset, e, n) + unsafe.compareAndSwapLong(t, offset, e, n): @nowarn("cat=deprecation") } def objCAS(t: Object, offset: Long, exp: Object, n: Object): Boolean = { if (debug) println(s"objCAS($t, $exp, $n)") - unsafe.compareAndSwapObject(t, offset, exp, n) + unsafe.compareAndSwapObject(t, offset, exp, n): @nowarn("cat=deprecation") } def setFlag(t: Object, offset: Long, v: Int, ord: Int): Unit = { @@ -147,7 +147,7 @@ object LazyVals { def get(t: Object, off: Long): Long = { if (debug) println(s"get($t, $off)") - unsafe.getLongVolatile(t, off) + unsafe.getLongVolatile(t, off): @nowarn("cat=deprecation") } // kept for backward compatibility From 245072ff182cc6321bc4bc207c0ab4caf5ef9c83 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Tue, 28 Jan 2025 09:23:07 -0800 Subject: [PATCH 043/505] Fix test --- compiler/test/dotty/tools/utils.scala | 4 ++-- tests/warn/i18564.scala | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/test/dotty/tools/utils.scala b/compiler/test/dotty/tools/utils.scala index a8c480088e08..49ea2d4d3873 100644 --- a/compiler/test/dotty/tools/utils.scala +++ b/compiler/test/dotty/tools/utils.scala @@ -101,10 +101,10 @@ def toolArgsParse(lines: List[String], filename: Option[String]): List[(String,S case toolArg(name, args) => List((name, args)) case _ => Nil } ++ - lines.flatMap { + lines.flatMap { case directiveOptionsArg(args) => List(("scalac", args)) case directiveJavacOptions(args) => List(("javac", args)) - case _ => Nil + case _ => Nil } import org.junit.Test diff --git a/tests/warn/i18564.scala b/tests/warn/i18564.scala index 3da41265015c..19682b7955f9 100644 --- a/tests/warn/i18564.scala +++ b/tests/warn/i18564.scala @@ -1,5 +1,5 @@ -//> using option -Wunused:imports +//> using options -Wunused:imports import scala.compiletime.* import scala.deriving.* From f2519e4c7f1cd76e1ed77e509ae32e7d4cc5458c Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Thu, 10 Apr 2025 17:09:19 +0200 Subject: [PATCH 044/505] Fix test [Cherry-picked 152a8cdc9a62f058d05185e48734a126b65137b3][modified] --- compiler/src/dotty/tools/dotc/ast/Trees.scala | 4 +- .../tools/dotc/transform/CheckUnused.scala | 31 ++- tests/semanticdb/metac.expect | 248 +++++++++--------- tests/warn/i15503f.scala | 9 - tests/warn/i19657-mega.scala | 2 +- tests/warn/i22371.scala | 8 - 6 files changed, 147 insertions(+), 155 deletions(-) delete mode 100644 tests/warn/i22371.scala diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 7652dcfc9928..dc8c2add27be 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -31,7 +31,7 @@ object Trees { /** Property key for backquoted identifiers and definitions */ val Backquoted: Property.StickyKey[Unit] = Property.StickyKey() - + val SyntheticUnit: Property.StickyKey[Unit] = Property.StickyKey() /** Trees take a parameter indicating what the type of their `tpe` field @@ -765,6 +765,7 @@ object Trees { override def isEmpty: Boolean = !hasType override def toString: String = s"TypeTree${if (hasType) s"[$typeOpt]" else ""}" + def isInferred = false } /** Tree that replaces a level 1 splices in pickled (level 0) quotes. @@ -787,6 +788,7 @@ object Trees { */ class InferredTypeTree[+T <: Untyped](implicit @constructorOnly src: SourceFile) extends TypeTree[T]: type ThisTree[+T <: Untyped] <: InferredTypeTree[T] + override def isInferred = true /** ref.type */ case class SingletonTypeTree[+T <: Untyped] private[ast] (ref: Tree[T])(implicit @constructorOnly src: SourceFile) diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index dc15bb80cbb6..bb5878737083 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -7,7 +7,7 @@ import dotty.tools.dotc.config.ScalaSettings import dotty.tools.dotc.core.Contexts.* import dotty.tools.dotc.core.Flags.* import dotty.tools.dotc.core.Names.{Name, SimpleName, DerivedName, TermName, termName} -import dotty.tools.dotc.core.NameOps.{isAnonymousFunctionName, isReplWrapperName} +import dotty.tools.dotc.core.NameOps.{isAnonymousFunctionName, isReplWrapperName, isContextFunction} import dotty.tools.dotc.core.NameKinds.{ContextBoundParamName, ContextFunctionParamName, WildcardParamName} import dotty.tools.dotc.core.StdNames.nme import dotty.tools.dotc.core.Symbols.{ClassSymbol, NoSymbol, Symbol, defn, isDeprecated, requiredClass, requiredModule} @@ -123,7 +123,7 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha override def transformTypeTree(tree: TypeTree)(using Context): tree.type = tree.tpe match case AnnotatedType(_, annot) => transformAllDeep(annot.tree) - case tpt if tpt.typeSymbol.exists => resolveUsage(tpt.typeSymbol, tpt.typeSymbol.name, NoPrefix) + case tpt if !tree.isInferred && tpt.typeSymbol.exists => resolveUsage(tpt.typeSymbol, tpt.typeSymbol.name, NoPrefix) case _ => tree @@ -557,7 +557,7 @@ object CheckUnused: val dd = defn m.isDeprecated || m.is(Synthetic) - || sym.name.is(ContextFunctionParamName) // a ubiquitous parameter + || sym.owner.name.isContextFunction // a ubiquitous parameter || sym.name.is(ContextBoundParamName) && sym.info.typeSymbol.isMarkerTrait // a ubiquitous parameter || m.hasAnnotation(dd.UnusedAnnot) // param of unused method || sym.info.typeSymbol.match // more ubiquity @@ -569,13 +569,17 @@ object CheckUnused: || sym.info.isInstanceOf[RefinedType] // can't be expressed as a context bound if ctx.settings.WunusedHas.implicits && !infos.skip(m) + && !m.isEffectivelyOverride && !allowed then if m.isPrimaryConstructor then val alias = m.owner.info.member(sym.name) if alias.exists then val aliasSym = alias.symbol - if aliasSym.is(ParamAccessor) && !infos.refs(alias.symbol) then + val checking = + aliasSym.isAllOf(PrivateParamAccessor, butNot = CaseAccessor) + || aliasSym.isAllOf(Protected | ParamAccessor, butNot = CaseAccessor) && m.owner.is(Given) + if checking && !infos.refs(alias.symbol) then warnAt(pos)(UnusedSymbol.implicitParams) else warnAt(pos)(UnusedSymbol.implicitParams) @@ -845,17 +849,24 @@ object CheckUnused: private val serializationNames: Set[TermName] = Set("readResolve", "readObject", "readObjectNoData", "writeObject", "writeReplace").map(termName(_)) - extension (sym: Symbol) - def isSerializationSupport(using Context): Boolean = + extension (sym: Symbol)(using Context) + def isSerializationSupport: Boolean = sym.is(Method) && serializationNames(sym.name.toTermName) && sym.owner.isClass && sym.owner.derivesFrom(defn.JavaSerializableClass) - def isCanEqual(using Context): Boolean = + def isCanEqual: Boolean = sym.isOneOf(GivenOrImplicit) && sym.info.finalResultType.baseClasses.exists(_.derivesFrom(defn.CanEqualClass)) - def isMarkerTrait(using Context): Boolean = + def isMarkerTrait: Boolean = sym.isClass && sym.info.allMembers.forall: d => val m = d.symbol !m.isTerm || m.isSelfSym || m.is(Method) && (m.owner == defn.AnyClass || m.owner == defn.ObjectClass) - + def isEffectivelyOverride: Boolean = + sym.is(Override) + || + sym.canMatchInheritedSymbols && { // inline allOverriddenSymbols using owner.info or thisType + val owner = sym.owner.asClass + val base = if owner.classInfo.selfInfo != NoType then owner.thisType else owner.info + base.baseClasses.drop(1).iterator.exists(sym.overriddenSymbol(_).exists) + } extension (sel: ImportSelector) def boundTpe: Type = sel.bound match case untpd.TypedSplice(tree) => tree.tpe @@ -893,7 +904,7 @@ object CheckUnused: else imp.expr.tpe.member(sel.name.toTermName).hasAltWith(_.symbol.isCanEqual) extension (pos: SrcPos) - def isZeroExtentSynthetic: Boolean = pos.span.isSynthetic && pos.span.start == pos.span.end + def isZeroExtentSynthetic: Boolean = pos.span.isSynthetic && pos.span.isZeroExtent extension [A <: AnyRef](arr: Array[A]) // returns `until` if not satisfied diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index 31a08dbb9e60..a89da0fb8aec 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -8,7 +8,6 @@ Text => empty Language => Scala Symbols => 9 entries Occurrences => 19 entries -Diagnostics => 2 entries Symbols: example/Access# => class Access extends Object { self: Access => +8 decls } @@ -42,10 +41,6 @@ Occurrences: [9:6..9:8): m7 <- example/Access#m7(). [9:11..9:14): ??? -> scala/Predef.`???`(). -Diagnostics: -[3:14..3:16): [warning] unused private member -[4:20..4:22): [warning] unused private member - expect/Advanced.scala --------------------- @@ -61,23 +56,23 @@ Synthetics => 3 entries Symbols: advanced/C# => class C [typeparam T ] extends Object { self: C[T] => +3 decls } -advanced/C#[T] => typeparam T +advanced/C#[T] => typeparam T advanced/C#``(). => primary ctor [typeparam T ](): C[T] advanced/C#t(). => method t => T advanced/HKClass# => class HKClass [typeparam F [typeparam T ] <: [U] =>> Tuple2[U, T]] extends Object { self: HKClass[F] => +3 decls } advanced/HKClass#[F] => typeparam F [typeparam T ] <: [U] =>> Tuple2[U, T] -advanced/HKClass#[F][T] => typeparam T -advanced/HKClass#[F][U] => typeparam U +advanced/HKClass#[F][T] => typeparam T +advanced/HKClass#[F][U] => typeparam U advanced/HKClass#``(). => primary ctor [typeparam F [typeparam T ] <: [U] =>> Tuple2[U, T]](): HKClass[F] -advanced/HKClass#``().[F][T] => typeparam T -advanced/HKClass#``().[F][U] => typeparam U +advanced/HKClass#``().[F][T] => typeparam T +advanced/HKClass#``().[F][U] => typeparam U advanced/HKClass#foo(). => method foo [typeparam T , typeparam U ](param x: F[T, U]): String advanced/HKClass#foo().(x) => param x: F[T, U] -advanced/HKClass#foo().[T] => typeparam T -advanced/HKClass#foo().[U] => typeparam U +advanced/HKClass#foo().[T] => typeparam T +advanced/HKClass#foo().[U] => typeparam U advanced/Structural# => class Structural extends Object { self: Structural => +6 decls } advanced/Structural#T# => trait T [typeparam A ] extends Object { self: T[A] => +4 decls } -advanced/Structural#T#[A] => typeparam A +advanced/Structural#T#[A] => typeparam A advanced/Structural#T#``(). => primary ctor [typeparam A ](): T[A] advanced/Structural#T#bar(). => method bar (param b: foo.B): Unit advanced/Structural#T#bar().(b) => param b: foo.B @@ -291,8 +286,8 @@ Symbols: annot/Alias. => final object Alias extends Object { self: Alias.type => +2 decls } annot/Alias.A# => type A = ClassAnnotation @param annot/Annotations# => @ClassAnnotation class Annotations [@TypeParameterAnnotation typeparam T ] extends Object { self: AnyRef & Annotations[T] => +6 decls } -annot/Annotations#S# => @TypeAnnotation type S -annot/Annotations#[T] => @TypeParameterAnnotation typeparam T +annot/Annotations#S# => @TypeAnnotation type S +annot/Annotations#[T] => @TypeParameterAnnotation typeparam T annot/Annotations#``(). => primary ctor [@TypeParameterAnnotation typeparam T ](@ParameterAnnotation param x: T): Annotations[T] annot/Annotations#``().(x) => @ParameterAnnotation param x: T annot/Annotations#field. => @FieldAnnotation val method field Int @@ -306,7 +301,7 @@ annot/B#throwing(). => @throws[Exception] method throwing => Nothing annot/B#x. => private[this] val method x Int annot/M. => @ObjectAnnotation final object M extends Object { self: M.type => +1 decls } annot/M.m(). => @MacroAnnotation macro m [typeparam TT ]: Int -annot/M.m().[TT] => typeparam TT +annot/M.m().[TT] => typeparam TT annot/T# => @TraitAnnotation trait T extends Object { self: T => +1 decls } annot/T#``(). => primary ctor (): T local0 => selfparam self: AnyRef @@ -399,10 +394,10 @@ example/Anonymous#bar2. => val method bar2 Bar example/Anonymous#foo. => val method foo Foo example/Anonymous#locally(). => method locally [typeparam A ](param x: A): A example/Anonymous#locally().(x) => param x: A -example/Anonymous#locally().[A] => typeparam A +example/Anonymous#locally().[A] => typeparam A example/Anonymous#m1(). => method m1 [typeparam T [type _ ]]: Nothing example/Anonymous#m1().[T] => typeparam T [type _ ] -example/Anonymous#m1().[T][_] => type _ +example/Anonymous#m1().[T][_] => type _ example/Anonymous#m2(). => method m2 => Map[_, List[_] forSome { type _ }] forSome { type _ } local0 => val local x: Function1[Int, Int] local1 => final class $anon extends Object with Foo { self: $anon => +1 decls } @@ -559,7 +554,7 @@ Text => empty Language => Scala Symbols => 108 entries Occurrences => 127 entries -Diagnostics => 4 entries +Diagnostics => 9 entries Synthetics => 2 entries Symbols: @@ -637,7 +632,7 @@ classes/C11#foo(). => inline macro foo => Int classes/C12# => class C12 extends Object { self: C12 => +8 decls } classes/C12#Context# => class Context extends Object { self: Context => +2 decls } classes/C12#Context#Expr# => type Expr [typeparam T ] -classes/C12#Context#Expr#[T] => typeparam T +classes/C12#Context#Expr#[T] => typeparam T classes/C12#Context#``(). => primary ctor (): Context classes/C12#``(). => primary ctor (): C12 classes/C12#foo1(). => macro foo1 (param x: Int): Int @@ -928,7 +923,7 @@ endmarkers/MultiCtor#``().(i) => val param i: Int endmarkers/MultiCtor#``(+1). => ctor (): MultiCtor endmarkers/MultiCtor#i. => val method i Int endmarkers/Stuff# => trait Stuff [typeparam A ] extends Object { self: Stuff[A] => +3 decls } -endmarkers/Stuff#[A] => typeparam A +endmarkers/Stuff#[A] => typeparam A endmarkers/Stuff#``(). => primary ctor [typeparam A ](): Stuff[A] endmarkers/Stuff#do(). => abstract method do => A endmarkers/TestObj. => final object TestObj extends Object { self: TestObj.type => +2 decls } @@ -1127,29 +1122,29 @@ _empty_/Enums.Directions.valueOf(). => method valueOf (param $name: String): Dir _empty_/Enums.Directions.valueOf().($name) => param $name: String _empty_/Enums.Directions.values(). => method values => Array[Directions] _empty_/Enums.Maybe# => abstract sealed enum class Maybe [covariant typeparam A ] extends Object with Enum { self: Maybe[A] => +2 decls } -_empty_/Enums.Maybe#[A] => covariant typeparam A +_empty_/Enums.Maybe#[A] => covariant typeparam A _empty_/Enums.Maybe#``(). => primary ctor [covariant typeparam A ](): Maybe[A] _empty_/Enums.Maybe. => final object Maybe extends Object { self: Maybe.type => +6 decls } _empty_/Enums.Maybe.Just# => final case enum class Just [covariant typeparam A ] extends Maybe[A] { self: Just[A] => +7 decls } -_empty_/Enums.Maybe.Just#[A] => covariant typeparam A +_empty_/Enums.Maybe.Just#[A] => covariant typeparam A _empty_/Enums.Maybe.Just#_1(). => method _1 => A _empty_/Enums.Maybe.Just#``(). => primary ctor [covariant typeparam A ](val param value: A): Just[A] _empty_/Enums.Maybe.Just#``().(value) => val param value: A _empty_/Enums.Maybe.Just#copy$default$1(). => method copy$default$1 [covariant typeparam A ]: A -_empty_/Enums.Maybe.Just#copy$default$1().[A] => typeparam A +_empty_/Enums.Maybe.Just#copy$default$1().[A] => typeparam A _empty_/Enums.Maybe.Just#copy(). => method copy [covariant typeparam A ](param value: A): Just[A] _empty_/Enums.Maybe.Just#copy().(value) => param value: A -_empty_/Enums.Maybe.Just#copy().[A] => typeparam A +_empty_/Enums.Maybe.Just#copy().[A] => typeparam A _empty_/Enums.Maybe.Just#ordinal(). => method ordinal => Int <: scala/reflect/Enum#ordinal(). _empty_/Enums.Maybe.Just#value. => val method value A _empty_/Enums.Maybe.Just. => final object Just extends Object { self: Just.type => +4 decls } _empty_/Enums.Maybe.Just.apply(). => method apply [typeparam A ](param value: A): Just[A] _empty_/Enums.Maybe.Just.apply().(value) => param value: A -_empty_/Enums.Maybe.Just.apply().[A] => typeparam A +_empty_/Enums.Maybe.Just.apply().[A] => typeparam A _empty_/Enums.Maybe.Just.toString(). => method toString => String <: scala/Any#toString(). _empty_/Enums.Maybe.Just.unapply(). => method unapply [typeparam A ](param x$1: Just[A]): Just[A] _empty_/Enums.Maybe.Just.unapply().(x$1) => param x$1: Just[A] -_empty_/Enums.Maybe.Just.unapply().[A] => typeparam A +_empty_/Enums.Maybe.Just.unapply().[A] => typeparam A _empty_/Enums.Maybe.None. => case val static enum method None Maybe[Nothing] _empty_/Enums.Maybe.fromOrdinal(). => method fromOrdinal (param ordinal: Int): Maybe[_] forSome { type _ } _empty_/Enums.Maybe.fromOrdinal().(ordinal) => param ordinal: Int @@ -1200,7 +1195,7 @@ _empty_/Enums.Suits.valueOf(). => method valueOf (param $name: String): Suits _empty_/Enums.Suits.valueOf().($name) => param $name: String _empty_/Enums.Suits.values(). => method values => Array[Suits] _empty_/Enums.Tag# => abstract sealed enum class Tag [typeparam A ] extends Object with Enum { self: Tag[A] => +2 decls } -_empty_/Enums.Tag#[A] => typeparam A +_empty_/Enums.Tag#[A] => typeparam A _empty_/Enums.Tag#``(). => primary ctor [typeparam A ](): Tag[A] _empty_/Enums.Tag. => final object Tag extends Object { self: Tag.type => +7 decls } _empty_/Enums.Tag.$values. => private[this] val method $values Array[Tag[_] forSome { type _ }] @@ -1231,33 +1226,33 @@ _empty_/Enums.WeekDays.valueOf(). => method valueOf (param $name: String): WeekD _empty_/Enums.WeekDays.valueOf().($name) => param $name: String _empty_/Enums.WeekDays.values(). => method values => Array[WeekDays] _empty_/Enums.`<:<`# => abstract sealed enum class <:< [contravariant typeparam A , typeparam B ] extends Object with Enum { self: <:<[A, B] => +3 decls } -_empty_/Enums.`<:<`#[A] => contravariant typeparam A -_empty_/Enums.`<:<`#[B] => typeparam B +_empty_/Enums.`<:<`#[A] => contravariant typeparam A +_empty_/Enums.`<:<`#[B] => typeparam B _empty_/Enums.`<:<`#``(). => primary ctor [contravariant typeparam A , typeparam B ](): <:<[A, B] _empty_/Enums.`<:<`. => final object <:< extends Object { self: <:<.type => +6 decls } _empty_/Enums.`<:<`.Refl# => final case enum class Refl [typeparam C ] extends <:<[C, C] { self: Refl[C] => +4 decls } -_empty_/Enums.`<:<`.Refl#[C] => typeparam C +_empty_/Enums.`<:<`.Refl#[C] => typeparam C _empty_/Enums.`<:<`.Refl#``(). => primary ctor [typeparam C ](): Refl[C] _empty_/Enums.`<:<`.Refl#copy(). => method copy [typeparam C ](): Refl[C] -_empty_/Enums.`<:<`.Refl#copy().[C] => typeparam C +_empty_/Enums.`<:<`.Refl#copy().[C] => typeparam C _empty_/Enums.`<:<`.Refl#ordinal(). => method ordinal => Int <: scala/reflect/Enum#ordinal(). _empty_/Enums.`<:<`.Refl. => final object Refl extends Object { self: Refl.type => +4 decls } _empty_/Enums.`<:<`.Refl.apply(). => method apply [typeparam C ](): Refl[C] -_empty_/Enums.`<:<`.Refl.apply().[C] => typeparam C +_empty_/Enums.`<:<`.Refl.apply().[C] => typeparam C _empty_/Enums.`<:<`.Refl.toString(). => method toString => String <: scala/Any#toString(). _empty_/Enums.`<:<`.Refl.unapply(). => method unapply [typeparam C ](param x$1: Refl[C]): true _empty_/Enums.`<:<`.Refl.unapply().(x$1) => param x$1: Refl[C] -_empty_/Enums.`<:<`.Refl.unapply().[C] => typeparam C +_empty_/Enums.`<:<`.Refl.unapply().[C] => typeparam C _empty_/Enums.`<:<`.`given_<:<_T_T`(). => final implicit given method given_<:<_T_T [typeparam T ]: <:<[T, T] -_empty_/Enums.`<:<`.`given_<:<_T_T`().[T] => typeparam T +_empty_/Enums.`<:<`.`given_<:<_T_T`().[T] => typeparam T _empty_/Enums.`<:<`.fromOrdinal(). => method fromOrdinal (param ordinal: Int): <:<[_, _] forSome { type _ ; type _ } _empty_/Enums.`<:<`.fromOrdinal().(ordinal) => param ordinal: Int _empty_/Enums.some1. => val method some1 Option[Int] _empty_/Enums.unwrap(). => method unwrap [typeparam A , typeparam B ](param opt: Option[A])(implicit given param ev: <:<[A, Option[B]]): Option[B] _empty_/Enums.unwrap().(ev) => implicit given param ev: <:<[A, Option[B]] _empty_/Enums.unwrap().(opt) => param opt: Option[A] -_empty_/Enums.unwrap().[A] => typeparam A -_empty_/Enums.unwrap().[B] => typeparam B +_empty_/Enums.unwrap().[A] => typeparam A +_empty_/Enums.unwrap().[B] => typeparam B local0 => param x: Option[B] Occurrences: @@ -1530,7 +1525,7 @@ Symbols: ext/DeckUsage. => final object DeckUsage extends Object { self: DeckUsage.type => +2 decls } ext/DeckUsage.deck. => val method deck Deck ext/Extension$package. => final package object ext extends Object { self: ext.type { opaque type Deck } => +9 decls } -ext/Extension$package.Deck# => opaque type Deck +ext/Extension$package.Deck# => opaque type Deck ext/Extension$package.Deck. => final object Deck extends Object { self: Deck.type => +2 decls } ext/Extension$package.Deck.fooSize(). => method fooSize (param data: Deck): Int ext/Extension$package.Deck.fooSize().(data) => param data: Deck @@ -1544,18 +1539,18 @@ ext/Extension$package.foo().(s) => param s: String ext/Extension$package.readInto(). => method readInto [typeparam T ](param s: String)(implicit given param x$2: Read[T]): Option[T] ext/Extension$package.readInto().(s) => param s: String ext/Extension$package.readInto().(x$2) => implicit given param x$2: Read[T] -ext/Extension$package.readInto().[T] => typeparam T +ext/Extension$package.readInto().[T] => typeparam T ext/Functor# => trait Functor [typeparam F [type _ ]] extends Object { self: Functor[F] => +3 decls } ext/Functor#[F] => typeparam F [type _ ] -ext/Functor#[F][_] => type _ +ext/Functor#[F][_] => type _ ext/Functor#``(). => primary ctor [typeparam F [type _ ]](): Functor[F] ext/Functor#map(). => abstract method map [typeparam T , typeparam U ](param t: F[T])(param f: Function1[T, U]): F[U] ext/Functor#map().(f) => param f: Function1[T, U] ext/Functor#map().(t) => param t: F[T] -ext/Functor#map().[T] => typeparam T -ext/Functor#map().[U] => typeparam U +ext/Functor#map().[T] => typeparam T +ext/Functor#map().[U] => typeparam U ext/Read# => trait Read [covariant typeparam T ] extends Object { self: Read[T] => +3 decls } -ext/Read#[T] => covariant typeparam T +ext/Read#[T] => covariant typeparam T ext/Read#``(). => primary ctor [covariant typeparam T ](): Read[T] ext/Read#fromString(). => abstract method fromString (param s: String): Option[T] ext/Read#fromString().(s) => param s: String @@ -1736,7 +1731,7 @@ Synthetics => 3 entries Symbols: a/b/Givens. => final object Givens extends Object { self: Givens.type => +13 decls } a/b/Givens.Monoid# => trait Monoid [typeparam A ] extends Object { self: Monoid[A] => +4 decls } -a/b/Givens.Monoid#[A] => typeparam A +a/b/Givens.Monoid#[A] => typeparam A a/b/Givens.Monoid#``(). => primary ctor [typeparam A ](): Monoid[A] a/b/Givens.Monoid#combine(). => abstract method combine (param x: A)(param y: A): A a/b/Givens.Monoid#combine().(x) => param x: A @@ -1744,7 +1739,7 @@ a/b/Givens.Monoid#combine().(y) => param y: A a/b/Givens.Monoid#empty(). => abstract method empty => A a/b/Givens.foo(). => method foo [typeparam A ](implicit given param A: Monoid[A]): A a/b/Givens.foo().(A) => implicit given param A: Monoid[A] -a/b/Givens.foo().[A] => typeparam A +a/b/Givens.foo().[A] => typeparam A a/b/Givens.given_Monoid_String. => final implicit given object given_Monoid_String extends Object with Monoid[String] { self: given_Monoid_String.type => +3 decls } a/b/Givens.given_Monoid_String.combine(). => method combine (param x: String)(param y: String): String <: a/b/Givens.Monoid#combine(). a/b/Givens.given_Monoid_String.combine().(x) => param x: String @@ -1759,13 +1754,13 @@ a/b/Givens.int2String#apply().(x) => param x: Int a/b/Givens.int2String(). => final implicit given inline macro int2String => int2String a/b/Givens.sayGoodbye(). => method sayGoodbye [typeparam B ](param any: B): String a/b/Givens.sayGoodbye().(any) => param any: B -a/b/Givens.sayGoodbye().[B] => typeparam B +a/b/Givens.sayGoodbye().[B] => typeparam B a/b/Givens.sayHello(). => method sayHello [typeparam A ](param any: A): String a/b/Givens.sayHello().(any) => param any: A -a/b/Givens.sayHello().[A] => typeparam A +a/b/Givens.sayHello().[A] => typeparam A a/b/Givens.saySoLong(). => method saySoLong [typeparam B ](param any: B): String a/b/Givens.saySoLong().(any) => param any: B -a/b/Givens.saySoLong().[B] => typeparam B +a/b/Givens.saySoLong().[B] => typeparam B a/b/Givens.soLong1. => val method soLong1 String Occurrences: @@ -1873,7 +1868,7 @@ example/ImplicitConversion#tuple. => val method tuple Tuple2[Int, Int] example/ImplicitConversion#x. => val method x Int example/ImplicitConversion. => final object ImplicitConversion extends Object { self: ImplicitConversion.type => +6 decls } example/ImplicitConversion.newAny2stringadd# => final implicit class newAny2stringadd [typeparam A ] extends AnyVal { self: newAny2stringadd[A] => +4 decls } -example/ImplicitConversion.newAny2stringadd#[A] => typeparam A +example/ImplicitConversion.newAny2stringadd#[A] => typeparam A example/ImplicitConversion.newAny2stringadd#`+`(). => method + (param other: String): String example/ImplicitConversion.newAny2stringadd#`+`().(other) => param other: String example/ImplicitConversion.newAny2stringadd#``(). => primary ctor [typeparam A ](param self: A): newAny2stringadd[A] @@ -1881,7 +1876,7 @@ example/ImplicitConversion.newAny2stringadd#``().(self) => param self: A example/ImplicitConversion.newAny2stringadd#self. => private val method self A example/ImplicitConversion.newAny2stringadd(). => final implicit method newAny2stringadd [typeparam A ](param self: A): newAny2stringadd[A] example/ImplicitConversion.newAny2stringadd().(self) => param self: A -example/ImplicitConversion.newAny2stringadd().[A] => typeparam A +example/ImplicitConversion.newAny2stringadd().[A] => typeparam A example/ImplicitConversion.newAny2stringadd. => final object newAny2stringadd extends Object { self: newAny2stringadd.type => +2 decls } Occurrences: @@ -2094,7 +2089,7 @@ givens/InventedNames$package.given_Double(). => final implicit given method give givens/InventedNames$package.given_Double().(x$1) => implicit given param x$1: Int givens/InventedNames$package.given_Float. => final implicit lazy val given method given_Float Float givens/InventedNames$package.given_List_T(). => final implicit given method given_List_T [typeparam T ]: List[T] -givens/InventedNames$package.given_List_T().[T] => typeparam T +givens/InventedNames$package.given_List_T().[T] => typeparam T givens/InventedNames$package.given_String. => final implicit lazy val given method given_String String givens/InventedNames$package.given_X. => final implicit given object given_X extends Object with X { self: given_X.type => +2 decls } givens/InventedNames$package.given_X.doX(). => method doX => Int <: givens/X#doX(). @@ -2106,11 +2101,11 @@ givens/InventedNames$package.given_Y#x$1. => protected implicit val given method givens/InventedNames$package.given_Y(). => final implicit given method given_Y (implicit given param x$1: X): given_Y givens/InventedNames$package.given_Y().(x$1) => implicit given param x$1: X givens/InventedNames$package.given_Z_T# => implicit given class given_Z_T [typeparam T ] extends Object with Z[T] { self: given_Z_T[T] => +3 decls } -givens/InventedNames$package.given_Z_T#[T] => typeparam T +givens/InventedNames$package.given_Z_T#[T] => typeparam T givens/InventedNames$package.given_Z_T#``(). => primary ctor [typeparam T ](): given_Z_T[T] givens/InventedNames$package.given_Z_T#doZ(). => method doZ => List[T] <: givens/Z#doZ(). givens/InventedNames$package.given_Z_T(). => final implicit given method given_Z_T [typeparam T ]: given_Z_T[T] -givens/InventedNames$package.given_Z_T().[T] => typeparam T +givens/InventedNames$package.given_Z_T().[T] => typeparam T givens/InventedNames$package.intValue. => final implicit lazy val given method intValue Int givens/InventedNames$package.x. => val method x given_X.type givens/InventedNames$package.y. => val method y given_Y @@ -2122,7 +2117,7 @@ givens/Y# => trait Y extends Object { self: Y => +2 decls } givens/Y#``(). => primary ctor (): Y givens/Y#doY(). => abstract method doY => String givens/Z# => trait Z [typeparam T ] extends Object { self: Z[T] => +3 decls } -givens/Z#[T] => typeparam T +givens/Z#[T] => typeparam T givens/Z#``(). => primary ctor [typeparam T ](): Z[T] givens/Z#doZ(). => abstract method doZ => List[T] @@ -2270,7 +2265,7 @@ Symbols: example/Local# => class Local extends Object { self: Local => +2 decls } example/Local#``(). => primary ctor (): Local example/Local#a(). => method a (): Int -local0 => typeparam A +local0 => typeparam A local1 => param a: A local2 => local id: [typeparam A ](param a: A): A @@ -2335,10 +2330,10 @@ example/MatchType$package.Concat# => type Concat [typeparam Xs <: Tuple, covari example/MatchType$package.Concat#[Xs] => typeparam Xs <: Tuple example/MatchType$package.Concat#[Ys] => covariant typeparam Ys <: Tuple example/MatchType$package.Elem# => type Elem [typeparam X ] = X match { String => Char, Array[t] => t, Iterable[t] => t } -example/MatchType$package.Elem#[X] => typeparam X -local0 => type t -local1 => type t -local2 => type x +example/MatchType$package.Elem#[X] => typeparam X +local0 => type t +local1 => type t +local2 => type x local3 => type xs <: Tuple Occurrences: @@ -2578,11 +2573,11 @@ Occurrences => 156 entries Symbols: example/Methods# => class Methods [typeparam T ] extends Object { self: Methods[T] => +44 decls } example/Methods#AList# => type AList [typeparam T ] = List[T] -example/Methods#AList#[T] => typeparam T +example/Methods#AList#[T] => typeparam T example/Methods#List# => class List [typeparam T ] extends Object { self: List[T] => +2 decls } -example/Methods#List#[T] => typeparam T +example/Methods#List#[T] => typeparam T example/Methods#List#``(). => primary ctor [typeparam T ](): List[T] -example/Methods#[T] => typeparam T +example/Methods#[T] => typeparam T example/Methods#``(). => primary ctor [typeparam T ](): Methods[T] example/Methods#`m8().`(). => method m8(). (): Nothing example/Methods#`m9().`# => class m9(). extends Object { self: m9(). => +1 decls } @@ -2610,7 +2605,7 @@ example/Methods#m7(). => method m7 [typeparam U ](param c: Methods[T], param l: example/Methods#m7().(c) => param c: Methods[T] example/Methods#m7().(evidence$1) => implicit param evidence$1: Ordering[U] example/Methods#m7().(l) => param l: List[U] -example/Methods#m7().[U] => typeparam U +example/Methods#m7().[U] => typeparam U example/Methods#m9(). => method m9 (param x: m9().): Nothing example/Methods#m9().(x) => param x: m9(). example/Methods#m10(). => method m10 (param x: List[T]): Nothing @@ -2970,18 +2965,18 @@ Occurrences => 18 entries Symbols: _empty_/NewModifiers$package. => final package object _empty_ extends Object { self: _empty_.type { opaque type OpaqueB } => +2 decls } -_empty_/NewModifiers$package.OpaqueB# => opaque type OpaqueB +_empty_/NewModifiers$package.OpaqueB# => opaque type OpaqueB _empty_/NewModifiers. => final object NewModifiers extends Object { self: NewModifiers.type { opaque type A } => +3 decls } -_empty_/NewModifiers.A# => opaque type A +_empty_/NewModifiers.A# => opaque type A _empty_/NewModifiers.foo. => val inline method foo "foo" _empty_/NewModifiersClass# => opaque class NewModifiersClass extends Object { self: Any { opaque type C } & NewModifiersClass => +5 decls } -_empty_/NewModifiersClass#C# => opaque type C +_empty_/NewModifiersClass#C# => opaque type C _empty_/NewModifiersClass#Nested# => opaque class Nested extends Object { self: Any { opaque type NestedOpaque } & Nested => +2 decls } -_empty_/NewModifiersClass#Nested#NestedOpaque# => opaque type NestedOpaque +_empty_/NewModifiersClass#Nested#NestedOpaque# => opaque type NestedOpaque _empty_/NewModifiersClass#Nested#``(). => primary ctor (): Nested _empty_/NewModifiersClass#``(). => primary ctor (): NewModifiersClass _empty_/NewModifiersTrait# => opaque trait NewModifiersTrait extends Object { self: Any { opaque type D } & NewModifiersTrait => +2 decls } -_empty_/NewModifiersTrait#D# => opaque type D +_empty_/NewModifiersTrait#D# => opaque type D _empty_/NewModifiersTrait#``(). => primary ctor (): NewModifiersTrait Occurrences: @@ -3069,13 +3064,13 @@ Occurrences => 49 entries Symbols: prefixes/C# => class C extends Object { self: C => +6 decls } prefixes/C#N. => final object N extends Object { self: N.type => +2 decls } -prefixes/C#N.U# => type U -prefixes/C#T# => type T +prefixes/C#N.U# => type U +prefixes/C#T# => type T prefixes/C#``(). => primary ctor (): C prefixes/C#k1(). => method k1 => U prefixes/C#m1(). => method m1 => T prefixes/M. => final object M extends Object { self: M.type => +3 decls } -prefixes/M.T# => type T +prefixes/M.T# => type T prefixes/M.n1(). => method n1 => T prefixes/O. => final object O extends C { self: O.type => +2 decls } prefixes/O.o1(). => method o1 => O.this.T @@ -3152,13 +3147,13 @@ Synthetics => 3 entries Symbols: example/C# => class C extends Object { self: C => +3 decls } -example/C#T1# => type T1 -example/C#T2# => type T2 +example/C#T1# => type T1 +example/C#T2# => type T2 example/C#``(). => primary ctor (): C example/PickOneRefinement_1# => class PickOneRefinement_1 [typeparam S <: SpecialRefinement { abstract method pickOne [typeparam T ](param as: T*): Option[String] }] extends Object { self: PickOneRefinement_1[S] => +3 decls } example/PickOneRefinement_1#[S] => typeparam S <: SpecialRefinement { abstract method pickOne [typeparam T ](param as: T*): Option[String] } example/PickOneRefinement_1#[S](as) => param as: T* -example/PickOneRefinement_1#[S][T] => typeparam T +example/PickOneRefinement_1#[S][T] => typeparam T example/PickOneRefinement_1#``(). => primary ctor [typeparam S <: SpecialRefinement { abstract method pickOne [typeparam T ](param as: T*): Option[String] }](): PickOneRefinement_1[S] example/PickOneRefinement_1#run(). => method run (param s: S, param as: String*): Option[String] example/PickOneRefinement_1#run().(as) => param as: String* @@ -3167,7 +3162,7 @@ example/PolyHolder# => trait PolyHolder extends Object { self: PolyHolder => +2 example/PolyHolder#``(). => primary ctor (): PolyHolder example/PolyHolder#foo(). => abstract method foo [typeparam T ](param t: T): Any example/PolyHolder#foo().(t) => param t: T -example/PolyHolder#foo().[T] => typeparam T +example/PolyHolder#foo().[T] => typeparam T example/RecOrRefined$package. => final package object example extends Object { self: example.type => +9 decls } example/RecOrRefined$package.C2# => type C2 = C { type T2 = T1 <: example/C#T2#; type T1 <: example/C#T1# } example/RecOrRefined$package.Person# => type Person = Record { abstract val method age Int; abstract val method name String } @@ -3181,9 +3176,9 @@ example/RecOrRefined$package.m4(). => method m4 (param x: PolyHolder { abstract example/RecOrRefined$package.m4().(x) => param x: PolyHolder { abstract method foo [typeparam T ](param t: T): T <: example/PolyHolder#foo(). } example/RecOrRefined$package.m5(). => method m5 [typeparam Z ](param x: Int): PolyHolder { abstract method foo [typeparam T ](param t: T): T <: example/PolyHolder#foo(). } example/RecOrRefined$package.m5().(x) => param x: Int -example/RecOrRefined$package.m5().[Z] => typeparam Z +example/RecOrRefined$package.m5().[Z] => typeparam Z example/RecOrRefined$package.m6# => type m6 [typeparam X ] = PolyHolder { abstract method foo [typeparam T ](param t: T): T <: example/PolyHolder#foo(). } -example/RecOrRefined$package.m6#[X] => typeparam X +example/RecOrRefined$package.m6#[X] => typeparam X example/Record# => class Record extends Object with Selectable { self: Record => +4 decls } example/Record#``(). => primary ctor (param elems: Tuple2[String, Any]*): Record example/Record#``().(elems) => param elems: Tuple2[String, Any]* @@ -3195,9 +3190,9 @@ example/SpecialRefinement# => trait SpecialRefinement extends Object { self: Spe example/SpecialRefinement#``(). => primary ctor (): SpecialRefinement example/SpecialRefinement#pickOne(). => abstract method pickOne [typeparam T ](param as: T*): Option[Any] example/SpecialRefinement#pickOne().(as) => param as: T* -example/SpecialRefinement#pickOne().[T] => typeparam T +example/SpecialRefinement#pickOne().[T] => typeparam T local0 => abstract method pickOne [typeparam T ](param as: T*): Option[String] -local1 => typeparam T +local1 => typeparam T local2 => param as: T* local3 => abstract method pickOne [typeparam T ](param as: T*): Option[String] <: example/SpecialRefinement#pickOne(). local4 => abstract val method x Int @@ -3205,14 +3200,14 @@ local5 => abstract val method x Int local6 => abstract method y => Int local7 => abstract val method x Int local8 => abstract method y => Int -local9 => type z -local10 => typeparam T +local9 => type z +local10 => typeparam T local11 => param t: T local12 => abstract method foo [typeparam T ](param t: T): T <: example/PolyHolder#foo(). -local13 => typeparam T +local13 => typeparam T local14 => param t: T local15 => abstract method foo [typeparam T ](param t: T): T <: example/PolyHolder#foo(). -local16 => typeparam T +local16 => typeparam T local17 => param t: T local18 => abstract method foo [typeparam T ](param t: T): T <: example/PolyHolder#foo(). local19 => abstract val method name String @@ -3501,6 +3496,7 @@ Text => empty Language => Scala Symbols => 62 entries Occurrences => 164 entries +Diagnostics => 3 entries Synthetics => 39 entries Symbols: @@ -3518,7 +3514,7 @@ example/Synthetic#Contexts.m4(). => method m4 => Nothing example/Synthetic#F# => class F extends Object { self: F => +1 decls } example/Synthetic#F#``(). => primary ctor (): F example/Synthetic#J# => class J [typeparam T ] extends Object { self: J[T] => +4 decls } -example/Synthetic#J#[T] => typeparam T +example/Synthetic#J#[T] => typeparam T example/Synthetic#J#``(). => primary ctor [typeparam T ]()(implicit param evidence$1: Manifest[T]): J[T] example/Synthetic#J#``().(evidence$1) => implicit param evidence$1: Manifest[T] example/Synthetic#J#arr. => val method arr Array[T] @@ -4227,11 +4223,11 @@ Occurrences => 18 entries Symbols: _empty_/Test_depmatch. => final object Test_depmatch extends Object { self: Test_depmatch.type => +4 decls } _empty_/Test_depmatch.Bar# => type Bar [typeparam T ] = T match { Unit => Unit } -_empty_/Test_depmatch.Bar#[T] => typeparam T +_empty_/Test_depmatch.Bar#[T] => typeparam T _empty_/Test_depmatch.Foo# => type Foo = Int { type U } _empty_/Test_depmatch.baz(). => inline macro baz (param foo: Foo): Unit _empty_/Test_depmatch.baz().(foo) => param foo: Foo -local0 => type U +local0 => type U local1 => val local v: Bar[foo.U] Occurrences: @@ -4287,7 +4283,7 @@ Occurrences => 33 entries Symbols: exports/example/Codec# => trait Codec [typeparam T ] extends Object with Decoder[T] with Encoder[T] { self: Codec[T] => +6 decls } -exports/example/Codec#[T] => typeparam T +exports/example/Codec#[T] => typeparam T exports/example/Codec#``(). => primary ctor [typeparam T ](param decode: Decoder[T], param encode: Encoder[T]): Codec[T] exports/example/Codec#``().(decode) => param decode: Decoder[T] exports/example/Codec#``().(encode) => param encode: Encoder[T] @@ -4298,12 +4294,12 @@ exports/example/Codec#encode(). => final method encode (param t: T): Array[Byte] exports/example/Codec#encode().(t) => param t: T exports/example/Codec#encode. => private[this] val method encode Encoder[T] exports/example/Decoder# => trait Decoder [covariant typeparam T ] extends Object { self: Decoder[T] => +3 decls } -exports/example/Decoder#[T] => covariant typeparam T +exports/example/Decoder#[T] => covariant typeparam T exports/example/Decoder#``(). => primary ctor [covariant typeparam T ](): Decoder[T] exports/example/Decoder#decode(). => abstract method decode (param a: Array[Byte]): T exports/example/Decoder#decode().(a) => param a: Array[Byte] exports/example/Encoder# => trait Encoder [contravariant typeparam T ] extends Object { self: Encoder[T] => +3 decls } -exports/example/Encoder#[T] => contravariant typeparam T +exports/example/Encoder#[T] => contravariant typeparam T exports/example/Encoder#``(). => primary ctor [contravariant typeparam T ](): Encoder[T] exports/example/Encoder#encode(). => abstract method encode (param t: T): Array[Byte] exports/example/Encoder#encode().(t) => param t: T @@ -4357,11 +4353,11 @@ Occurrences => 5 entries Symbols: exports/`exports-package$package`. => final package object exports extends Object { self: exports.type => +4 decls } exports/`exports-package$package`.Codec# => final type Codec [typeparam T ] = Codec[T] -exports/`exports-package$package`.Codec#[T] => typeparam T +exports/`exports-package$package`.Codec#[T] => typeparam T exports/`exports-package$package`.Decoder# => final type Decoder [typeparam T ] = Decoder[T] -exports/`exports-package$package`.Decoder#[T] => typeparam T +exports/`exports-package$package`.Decoder#[T] => typeparam T exports/`exports-package$package`.Encoder# => final type Encoder [typeparam T ] = Encoder[T] -exports/`exports-package$package`.Encoder#[T] => typeparam T +exports/`exports-package$package`.Encoder#[T] => typeparam T Occurrences: [0:8..0:15): exports <- exports/ @@ -4403,35 +4399,35 @@ Occurrences => 54 entries Symbols: hk/EitherMonad# => class EitherMonad [typeparam T ] extends Object with Monad[[E] =>> Either[T, E]] { self: EitherMonad[T] => +2 decls } -hk/EitherMonad#[E] => typeparam E -hk/EitherMonad#[T] => typeparam T +hk/EitherMonad#[E] => typeparam E +hk/EitherMonad#[T] => typeparam T hk/EitherMonad#``(). => primary ctor [typeparam T ](): EitherMonad[T] -hk/EitherMonad#``().[E] => typeparam E +hk/EitherMonad#``().[E] => typeparam E hk/Monad# => trait Monad [typeparam M [type _ ]] extends Object { self: Monad[M] => +4 decls } hk/Monad#[M] => typeparam M [type _ ] -hk/Monad#[M][_] => type _ +hk/Monad#[M][_] => type _ hk/Monad#``(). => primary ctor [typeparam M [type _ ]](): Monad[M] hk/Monad#flatMap(). => method flatMap [typeparam A , typeparam B ](param m: M[A])(param f: Function1[A, M[B]]): M[B] hk/Monad#flatMap().(f) => param f: Function1[A, M[B]] hk/Monad#flatMap().(m) => param m: M[A] -hk/Monad#flatMap().[A] => typeparam A -hk/Monad#flatMap().[B] => typeparam B +hk/Monad#flatMap().[A] => typeparam A +hk/Monad#flatMap().[B] => typeparam B hk/Monad#pure(). => method pure [typeparam A ](param a: A): M[A] hk/Monad#pure().(a) => param a: A -hk/Monad#pure().[A] => typeparam A +hk/Monad#pure().[A] => typeparam A hk/hk$package. => final package object hk extends Object { self: hk.type => +5 decls } hk/hk$package.Id# => type Id [typeparam A ] = A -hk/hk$package.Id#[A] => typeparam A +hk/hk$package.Id#[A] => typeparam A hk/hk$package.MapEither# => type MapEither [typeparam K ] = [L] =>> [R] =>> Map[K, Either[L, R]] -hk/hk$package.MapEither#[K] => typeparam K -hk/hk$package.MapEither#[L] => typeparam L -hk/hk$package.MapEither#[R] => typeparam R +hk/hk$package.MapEither#[K] => typeparam K +hk/hk$package.MapEither#[L] => typeparam L +hk/hk$package.MapEither#[R] => typeparam R hk/hk$package.MapKV# => type MapKV [typeparam K ] = [V] =>> Map[K, V] -hk/hk$package.MapKV#[K] => typeparam K -hk/hk$package.MapKV#[V] => typeparam V +hk/hk$package.MapKV#[K] => typeparam K +hk/hk$package.MapKV#[V] => typeparam V hk/hk$package.MapV# => type MapV [type _ ] = [V] =>> Map[String, V] -hk/hk$package.MapV#[V] => typeparam V -hk/hk$package.MapV#[_] => type _ +hk/hk$package.MapV#[V] => typeparam V +hk/hk$package.MapV#[_] => type _ Occurrences: [0:8..0:10): hk <- hk/ @@ -4771,11 +4767,11 @@ _empty_/Concrete#``(). => primary ctor (): Concrete _empty_/Concrete#nullary2(). => method nullary2 => Int <: _empty_/NullaryTest#nullary2(). _empty_/Concrete#nullary3(). => method nullary3 => List[Int] <: _empty_/NullaryTest#nullary3(). _empty_/NullaryTest# => abstract class NullaryTest [typeparam T , typeparam m [typeparam s ]] extends Object { self: NullaryTest[T, m] => +9 decls } -_empty_/NullaryTest#[T] => typeparam T +_empty_/NullaryTest#[T] => typeparam T _empty_/NullaryTest#[m] => typeparam m [typeparam s ] -_empty_/NullaryTest#[m][s] => typeparam s +_empty_/NullaryTest#[m][s] => typeparam s _empty_/NullaryTest#``(). => primary ctor [typeparam T , typeparam m [typeparam s ]](): NullaryTest[T, m] -_empty_/NullaryTest#``().[m][s] => typeparam s +_empty_/NullaryTest#``().[m][s] => typeparam s _empty_/NullaryTest#nullary(). => method nullary => String _empty_/NullaryTest#nullary2(). => abstract method nullary2 => T _empty_/NullaryTest#nullary3(). => abstract method nullary3 => m[T] @@ -4979,9 +4975,9 @@ flags/p/package.AA#x. => private[this] val method x Int flags/p/package.AA#y. => val method y Int flags/p/package.AA#z(). => var method z Int flags/p/package.C# => abstract class C [covariant typeparam T , contravariant typeparam U , typeparam V ] extends Object { self: C[T, U, V] => +10 decls } -flags/p/package.C#[T] => covariant typeparam T -flags/p/package.C#[U] => contravariant typeparam U -flags/p/package.C#[V] => typeparam V +flags/p/package.C#[T] => covariant typeparam T +flags/p/package.C#[U] => contravariant typeparam U +flags/p/package.C#[V] => typeparam V flags/p/package.C#``(). => primary ctor [covariant typeparam T , contravariant typeparam U , typeparam V ](param x: T, param y: U, param z: V): C[T, U, V] flags/p/package.C#``().(x) => param x: T flags/p/package.C#``().(y) => param y: U @@ -4994,11 +4990,11 @@ flags/p/package.C#x. => private[this] val method x T flags/p/package.C#y. => private[this] val method y U flags/p/package.C#z. => private[this] val method z V flags/p/package.S# => class S [@specialized typeparam T ] extends Object { self: S[T] => +2 decls } -flags/p/package.S#[T] => @specialized typeparam T +flags/p/package.S#[T] => @specialized typeparam T flags/p/package.S#``(). => primary ctor [@specialized typeparam T ](): S[T] flags/p/package.T1# => type T1 = Int flags/p/package.T2# => type T2 [typeparam T ] = S[T] -flags/p/package.T2#[T] => typeparam T +flags/p/package.T2#[T] => typeparam T flags/p/package.U# => type U <: Int flags/p/package.V# => type V >: Int flags/p/package.X. => final case object X extends Object with Product with Serializable { self: X.type => +1 decls } @@ -5009,14 +5005,14 @@ flags/p/package.Z#``(). => primary ctor (): Z flags/p/package.`y_=`(). => protected var method y_= (param x$1: Int): Unit flags/p/package.`y_=`().(x$1) => param x$1: Int flags/p/package.m(). => macro m [typeparam TT ]: Int -flags/p/package.m().[TT] => typeparam TT +flags/p/package.m().[TT] => typeparam TT flags/p/package.x. => private[flags/p/] lazy val method x Int flags/p/package.xs1. => val method xs1 Nothing flags/p/package.y(). => protected implicit var method y Int flags/p/package.z(). => method z (param pp: Int): Int flags/p/package.z().(pp) => param pp: Int local0 => val local xs2: Nothing -local1 => type t +local1 => type t Occurrences: [0:8..0:13): flags <- flags/ @@ -5131,7 +5127,7 @@ local3 => final class $anon extends Object { self: $anon => +2 decls } local5 => final class $anon extends M with N { self: $anon => +1 decls } local7 => method k => Int local8 => final class $anon extends M with N { self: $anon => +2 decls } -local10 => typeparam T +local10 => typeparam T local11 => type L [typeparam T ] = List[T] types/B# => class B extends Object { self: B => +1 decls } types/B#``(). => primary ctor (): B @@ -5176,7 +5172,7 @@ types/Test.C#ClassInfoType2# => class ClassInfoType2 extends B { self: ClassInfo types/Test.C#ClassInfoType2#``(). => primary ctor (): ClassInfoType2 types/Test.C#ClassInfoType2#x(). => method x => Int types/Test.C#ClassInfoType3# => trait ClassInfoType3 [typeparam T ] extends Object { self: ClassInfoType3[T] => +2 decls } -types/Test.C#ClassInfoType3#[T] => typeparam T +types/Test.C#ClassInfoType3#[T] => typeparam T types/Test.C#ClassInfoType3#``(). => primary ctor [typeparam T ](): ClassInfoType3[T] types/Test.C#Either. => val method Either Either.type types/Test.C#MethodType. => final object MethodType extends Object { self: MethodType.type => +7 decls } @@ -5186,7 +5182,7 @@ types/Test.C#MethodType.m5(). => method m5 (param x: Int): Int types/Test.C#MethodType.m5().(x) => param x: Int types/Test.C#MethodType.m6(). => method m6 [typeparam T ](param x: T): T types/Test.C#MethodType.m6().(x) => param x: T -types/Test.C#MethodType.m6().[T] => typeparam T +types/Test.C#MethodType.m6().[T] => typeparam T types/Test.C#MethodType.x1(). => method x1 => Int types/Test.C#MethodType.x2(). => method x2 => Int types/Test.C#RepeatedType# => case class RepeatedType extends Object with Product with Serializable { self: RepeatedType => +4 decls } @@ -5203,15 +5199,15 @@ types/Test.C#RepeatedType.toString(). => method toString => String <: scala/Any# types/Test.C#RepeatedType.unapplySeq(). => method unapplySeq (param x$1: RepeatedType): RepeatedType types/Test.C#RepeatedType.unapplySeq().(x$1) => param x$1: RepeatedType types/Test.C#TypeType. => final object TypeType extends Object { self: TypeType.type => +6 decls } -types/Test.C#TypeType.T1# => type T1 +types/Test.C#TypeType.T1# => type T1 types/Test.C#TypeType.T4# => type T4 = C types/Test.C#TypeType.T5# => type T5 [typeparam U ] = U -types/Test.C#TypeType.T5#[U] => typeparam U +types/Test.C#TypeType.T5#[U] => typeparam U types/Test.C#TypeType.m2(). => method m2 [typeparam T2 = C]: Nothing types/Test.C#TypeType.m2().[T2] => typeparam T2 = C types/Test.C#TypeType.m3(). => method m3 [typeparam M3 [type _ ]]: Nothing types/Test.C#TypeType.m3().[M3] => typeparam M3 [type _ ] -types/Test.C#TypeType.m3().[M3][_] => type _ +types/Test.C#TypeType.m3().[M3][_] => type _ types/Test.C#``(). => primary ctor (): C types/Test.C#annType1. => val method annType1 T @ann[T] types/Test.C#annType2. => val method annType2 T @ann1 @ann2 @@ -5234,7 +5230,7 @@ types/Test.C#thisType1. => val method thisType1 C.this.type types/Test.C#thisType2. => val method thisType2 C.this.type types/Test.C#typeLambda1(). => method typeLambda1 [typeparam M [type _ ]]: Nothing types/Test.C#typeLambda1().[M] => typeparam M [type _ ] -types/Test.C#typeLambda1().[M][_] => type _ +types/Test.C#typeLambda1().[M][_] => type _ types/Test.C#typeRef1. => val method typeRef1 C types/Test.C#typeRef2. => val method typeRef2 p.C types/Test.C#typeRef3. => val method typeRef3 T#C @@ -5259,7 +5255,7 @@ types/Test.N# => trait N extends Object { self: N => +2 decls } types/Test.N#``(). => primary ctor (): N types/Test.N#n(). => method n => Int types/ann# => class ann [typeparam T ] extends Annotation with StaticAnnotation { self: ann[T] => +3 decls } -types/ann#[T] => typeparam T +types/ann#[T] => typeparam T types/ann#``(). => primary ctor [typeparam T ](param x: T): ann[T] types/ann#``().(x) => param x: T types/ann#x. => private[this] val method x T @@ -5517,7 +5513,7 @@ Occurrences: [119:39..119:42): Int -> scala/Int# Diagnostics: -[5:13..5:14): [warning] unused explicit parameter +[96:13..96:14): [warning] unused explicit parameter Synthetics: [68:20..68:24):@ann => *[Int] diff --git a/tests/warn/i15503f.scala b/tests/warn/i15503f.scala index 0550f82d9398..9d464bbc1973 100644 --- a/tests/warn/i15503f.scala +++ b/tests/warn/i15503f.scala @@ -33,15 +33,6 @@ object Example: case '{ ${Expr(opt)} : Some[T] } => Some(opt) case _ => None -object ExampleWithoutWith: - import scala.quoted.* - given [T] => (Type[T], FromExpr[T]) => FromExpr[Option[T]]: - def unapply(x: Expr[Option[T]])(using Quotes) = x match - case '{ Option[T](${Expr(y)}) } => Some(Option(y)) - case '{ None } => Some(None) - case '{ ${Expr(opt)} : Some[T] } => Some(opt) - case _ => None - //absolving names on matches of quote trees requires consulting non-abstract types in QuotesImpl object Unmatched: import scala.quoted.* diff --git a/tests/warn/i19657-mega.scala b/tests/warn/i19657-mega.scala index 07411ee73fb1..eeeb33ab3da7 100644 --- a/tests/warn/i19657-mega.scala +++ b/tests/warn/i19657-mega.scala @@ -1,4 +1,4 @@ -//> using options -Wshadow:type-parameter-shadow -Wunused:all +//> using options -Xlint:type-parameter-shadow -Wunused:all class F[X, M[N[X]]]: // warn private def x[X] = toString // warn // warn diff --git a/tests/warn/i22371.scala b/tests/warn/i22371.scala deleted file mode 100644 index 00f5b66695e0..000000000000 --- a/tests/warn/i22371.scala +++ /dev/null @@ -1,8 +0,0 @@ -//> using options -Werror -Wunused:all -import scala.compiletime.deferred - -class Context - -trait Foo: - given context: Context = deferred - given () => Context = deferred From 9f53f2d6f1fc6b3ea93b558c614bd90e44dcfdd0 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Mon, 3 Feb 2025 10:53:24 -0800 Subject: [PATCH 045/505] Check span.exists where necessary --- .../tools/dotc/transform/CheckUnused.scala | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index bb5878737083..29fef0843902 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -66,14 +66,14 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha // import x.y; y may be rewritten x.y, also import x.z as y override def transformSelect(tree: Select)(using Context): tree.type = val name = tree.removeAttachment(OriginalName).getOrElse(nme.NO_NAME) - if tree.span.isSynthetic && tree.symbol == defn.TypeTest_unapply then + if tree.srcPos.isSynthetic && tree.symbol == defn.TypeTest_unapply then tree.qualifier.tpe.underlying.finalResultType match case AppliedType(_, args) => // tycon.typeSymbol == defn.TypeTestClass val res = args(1) // T in TypeTest[-S, T] val target = res.dealias.typeSymbol resolveUsage(target, target.name, res.importPrefix.skipPackageObject) // case _: T => case _ => - else if tree.qualifier.span.isSynthetic || name.exists(_ != tree.symbol.name) then + else if tree.qualifier.srcPos.isSynthetic || name.exists(_ != tree.symbol.name) then if !ignoreTree(tree) then resolveUsage(tree.symbol, name, tree.qualifier.tpe) else @@ -592,12 +592,12 @@ object CheckUnused: warnAt(pos)(UnusedSymbol.localDefs) def checkPatvars() = - // convert the one non-synthetic span so all are comparable + // convert the one non-synthetic span so all are comparable; filter NoSpan below def uniformPos(sym: Symbol, pos: SrcPos): SrcPos = if pos.span.isSynthetic then pos else pos.sourcePos.withSpan(pos.span.toSynthetic) // patvars in for comprehensions share the pos of where the name was introduced val byPos = infos.pats.groupMap(uniformPos(_, _))((sym, pos) => sym) - for (pos, syms) <- byPos if !syms.exists(_.hasAnnotation(defn.UnusedAnnot)) do + for (pos, syms) <- byPos if pos.span.exists && !syms.exists(_.hasAnnotation(defn.UnusedAnnot)) do if !syms.exists(infos.refs(_)) then if !syms.exists(v => !v.isLocal && !v.is(Private)) then warnAt(pos)(UnusedSymbol.patVars) @@ -658,7 +658,10 @@ object CheckUnused: val selector = textAt(sel.srcPos) // keep original s"$qual.$selector" // don't succumb to vagaries of show // begin actionable - val sortedImps = infos.imps.keySet.nn.asScala.toArray.sortBy(_.srcPos.span.point) // sorted by pos + val sortedImps = infos.imps.keySet.nn.asScala + .filter(_.srcPos.span.exists) // extra caution + .toArray + .sortBy(_.srcPos.span.point) // sorted by pos, not sort in place var index = 0 while index < sortedImps.length do val nextImport = sortedImps.indexSatisfying(from = index + 1)(_.isPrimaryClause) // next import statement @@ -757,7 +760,11 @@ object CheckUnused: if ctx.settings.WunusedHas.imports || ctx.settings.WunusedHas.strictNoImplicitWarn then checkImports() - warnings.result().sortBy(_._2.span.point) + def sortOrder(msgInfo: MessageInfo): Int = + val srcPos = msgInfo._2 + if srcPos.span.exists then srcPos.span.point else 0 + + warnings.result().sortBy(sortOrder) end warnings // Specific exclusions @@ -881,8 +888,7 @@ object CheckUnused: extension (imp: Import) /** Is it the first import clause in a statement? `a.x` in `import a.x, b.{y, z}` */ def isPrimaryClause(using Context): Boolean = - val span = imp.srcPos.span - span.start != span.point // primary clause starts at `import` keyword + imp.srcPos.span.pointDelta > 0 // primary clause starts at `import` keyword with point at clause proper /** Generated import of cases from enum companion. */ def isGeneratedByEnum(using Context): Boolean = @@ -905,6 +911,7 @@ object CheckUnused: extension (pos: SrcPos) def isZeroExtentSynthetic: Boolean = pos.span.isSynthetic && pos.span.isZeroExtent + def isSynthetic: Boolean = pos.span.isSynthetic && pos.span.exists extension [A <: AnyRef](arr: Array[A]) // returns `until` if not satisfied From 975f776d731a9621aec7940e8b41377af923fe3c Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Sat, 19 Apr 2025 13:01:43 +0200 Subject: [PATCH 046/505] Check span.exists where necessary [Cherry-picked 7ad8418c6cc53a6003b8962bc8e09bbbb9861547][modified] From 9093057800f206a178e0b229f52c8fe33ab3557f Mon Sep 17 00:00:00 2001 From: Joel Wilsson Date: Fri, 30 Aug 2024 16:02:39 +0200 Subject: [PATCH 047/505] Handle NoType in TypeComparer.disjointnessBoundary Closes #20265 --- tests/neg/i20265.check | 28 ++++++++++++++++++++++++++++ tests/neg/i20265.scala | 23 +++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 tests/neg/i20265.check create mode 100644 tests/neg/i20265.scala diff --git a/tests/neg/i20265.check b/tests/neg/i20265.check new file mode 100644 index 000000000000..a55e4eba7c45 --- /dev/null +++ b/tests/neg/i20265.check @@ -0,0 +1,28 @@ +-- [E172] Type Error: tests/neg/i20265.scala:22:95 --------------------------------------------------------------------- +22 | println(summon[((String --> Unit) * (String --> Unit)) =:= Hinze[(String + String) --> Unit]]) // error + | ^ + | Cannot prove that (String --> Unit) * (String --> Unit) =:= Hinze[String + String --> Unit]. + | + | Note: a match type could not be fully reduced: + | + | trying to reduce Hinze[String + String --> Unit] + | failed since selector (String + String --> Unit)#unfix + | does not match case k1 + k2 --> v => Hinze[k1 --> v] * Hinze[k2 --> v] + | and cannot be shown to be disjoint from it either. + | Therefore, reduction cannot advance to the remaining case + | + | case k1 * k2 --> v => k1 --> Hinze[k2 --> v] +-- [E172] Type Error: tests/neg/i20265.scala:23:66 --------------------------------------------------------------------- +23 | println(summon[String =:= Hinze[Fix[Lambda[String]#L] --> Unit]]) // error + | ^ + | Cannot prove that String =:= Hinze[Fix[Lambda[String]#L] --> Unit]. + | + | Note: a match type could not be fully reduced: + | + | trying to reduce Hinze[Fix[Lambda[String]#L] --> Unit] + | failed since selector (Fix[Lambda[String]#L] --> Unit)#unfix + | does not match case k1 + k2 --> v => Hinze[k1 --> v] * Hinze[k2 --> v] + | and cannot be shown to be disjoint from it either. + | Therefore, reduction cannot advance to the remaining case + | + | case k1 * k2 --> v => k1 --> Hinze[k2 --> v] diff --git a/tests/neg/i20265.scala b/tests/neg/i20265.scala new file mode 100644 index 000000000000..1d312188ae99 --- /dev/null +++ b/tests/neg/i20265.scala @@ -0,0 +1,23 @@ +//> using options -source:3.3 + +trait Poly +trait -->[X, Y] extends Poly +trait +[X, Y] extends Poly +trait *[X, Y] extends Poly + +type Hinze[X <: Fix[?]] = X#unfix match + case (k1 + k2) --> v => Hinze[(k1 --> v)] * Hinze[(k2 --> v)] + case (k1 * k2) --> v => k1 --> Hinze[(k2 --> v)] + +trait Lambda[V]: + type Abs[X] = V * X + type App[X] = X * X + type L[X] = V + Abs[X] + App[X] + +trait Fix[F[X]]: + type unfix = F[Fix[F]] + +@main +def m = + println(summon[((String --> Unit) * (String --> Unit)) =:= Hinze[(String + String) --> Unit]]) // error + println(summon[String =:= Hinze[Fix[Lambda[String]#L] --> Unit]]) // error From 4b3ac8bd4adfbb5e8e6da1cd4501b5c2f008d221 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Mon, 21 Apr 2025 13:51:54 +0200 Subject: [PATCH 048/505] Handle NoType in TypeComparer.disjointnessBoundary Closes #20265 [Cherry-picked c00f2146504ff1c15b15230f067d09750de1a618][modified] From 16aaa27178dcc39ae844fb655cb8023ab4141c86 Mon Sep 17 00:00:00 2001 From: Joel Wilsson Date: Sun, 26 Jan 2025 17:51:29 +0100 Subject: [PATCH 049/505] Add test that crashes without -source 3.3 [Cherry-picked 3d8a70fe81381b873236529401f6a0740c12bf41] --- tests/neg/i20265-1.check | 5 +++++ tests/neg/i20265-1.scala | 9 +++++++++ 2 files changed, 14 insertions(+) create mode 100644 tests/neg/i20265-1.check create mode 100644 tests/neg/i20265-1.scala diff --git a/tests/neg/i20265-1.check b/tests/neg/i20265-1.check new file mode 100644 index 000000000000..6eb9f4cfe5c6 --- /dev/null +++ b/tests/neg/i20265-1.check @@ -0,0 +1,5 @@ +-- Error: tests/neg/i20265-1.scala:4:6 --------------------------------------------------------------------------------- +4 | def apply(args: Tuple.Map[m.MirroredElemTypes, Expr]): Expr[T] = ??? // error + | ^ + | non-private method apply in trait Ops refers to private given instance m + | in its type signature (args: Tuple.Map[Ops.this.m.MirroredElemTypes, Expr]): Expr[T] diff --git a/tests/neg/i20265-1.scala b/tests/neg/i20265-1.scala new file mode 100644 index 000000000000..085d387ae901 --- /dev/null +++ b/tests/neg/i20265-1.scala @@ -0,0 +1,9 @@ +trait Expr[T] + +trait Ops[T](using m: scala.deriving.Mirror.ProductOf[T]) { + def apply(args: Tuple.Map[m.MirroredElemTypes, Expr]): Expr[T] = ??? // error +} + +case class P(a: Int) +object P extends Ops[P] + From 2bd0e2d3d276b2d21042737c9cf2d083c1cd6b77 Mon Sep 17 00:00:00 2001 From: Rocco Mathijn Andela Date: Wed, 29 Jan 2025 11:43:10 +0100 Subject: [PATCH 050/505] Warn on bad extensions of aliases (#22362) Fixes https://github.com/scala/scala3/issues/22233 --- compiler/src/dotty/tools/dotc/typer/RefChecks.scala | 2 +- tests/{pos => warn}/ext-override.scala | 2 +- tests/warn/i16743.check | 7 +++++++ tests/warn/i16743.scala | 2 +- tests/warn/i22233.scala | 1 + 5 files changed, 11 insertions(+), 3 deletions(-) rename tests/{pos => warn}/ext-override.scala (89%) create mode 100644 tests/warn/i22233.scala diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 87768e8a2026..bb58bb05fadf 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -1089,7 +1089,7 @@ object RefChecks { } } .exists - if !target.typeSymbol.denot.isAliasType && !target.typeSymbol.denot.isOpaqueAlias && hidden + if !target.typeSymbol.isOpaqueAlias && hidden then report.warning(ExtensionNullifiedByMember(sym, target.typeSymbol), sym.srcPos) end checkExtensionMethods diff --git a/tests/pos/ext-override.scala b/tests/warn/ext-override.scala similarity index 89% rename from tests/pos/ext-override.scala rename to tests/warn/ext-override.scala index d08439e13c9a..7c082695cbaa 100644 --- a/tests/pos/ext-override.scala +++ b/tests/warn/ext-override.scala @@ -7,6 +7,6 @@ trait Foo[T]: class Bla: def hi: String = "hi" object Bla: - given Foo[Bla] with + given Foo[Bla]: extension (x: Bla) def hi: String = x.hi diff --git a/tests/warn/i16743.check b/tests/warn/i16743.check index 6fa1f2c83357..9fdf80e71f2b 100644 --- a/tests/warn/i16743.check +++ b/tests/warn/i16743.check @@ -1,3 +1,10 @@ +-- [E194] Potential Issue Warning: tests/warn/i16743.scala:90:8 -------------------------------------------------------- +90 | def length() = 42 // warn This extension method will be shadowed by .length() on String. + | ^ + | Extension method length will never be selected from type String + | because String already has a member with the same name and compatible parameter types. + | + | longer explanation available when compiling with `-explain` -- [E194] Potential Issue Warning: tests/warn/i16743.scala:30:6 -------------------------------------------------------- 30 | def t = 27 // warn | ^ diff --git a/tests/warn/i16743.scala b/tests/warn/i16743.scala index 4c9c99cf30d0..e8860aeabaae 100644 --- a/tests/warn/i16743.scala +++ b/tests/warn/i16743.scala @@ -87,7 +87,7 @@ class Depends: object Depending: extension (using depends: Depends)(x: depends.Thing) def y = 42 - def length() = 42 // nowarn see Quote above + def length() = 42 // warn This extension method will be shadowed by .length() on String. def f(using d: Depends) = d.thing.y def g(using d: Depends) = d.thing.length() diff --git a/tests/warn/i22233.scala b/tests/warn/i22233.scala new file mode 100644 index 000000000000..08caea1c25fb --- /dev/null +++ b/tests/warn/i22233.scala @@ -0,0 +1 @@ +extension (s: String) def length = 42 // warn From 68e6ec2d1737189f056697e3711d469060546f42 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Mon, 21 Apr 2025 13:52:55 +0200 Subject: [PATCH 051/505] Warn on bad extensions of aliases (#22362) Fixes https://github.com/scala/scala3/issues/22233 [Cherry-picked 5fe57c299b68c52f4596e707904513bffa14848f][modified] From 9e05dba93785bedcfc3b43c5aae0e7c6412a34ab Mon Sep 17 00:00:00 2001 From: som-snytt Date: Wed, 29 Jan 2025 02:45:59 -0800 Subject: [PATCH 052/505] No outdent at eof (#22435) Fixes #22332 The reference does not mention ``. `` insertion does not require a particular next token, though some next tokens affect it (that is, leading infix or tokens that close an indentation region). It does require a "first token on the next line", for which we may take `` as the lack of a token. Of course, ordinary error messages say `eof`. The same text with an opening brace is unchanged: ``` 5 | | ^ | '}' expected, but eof found ``` [Cherry-picked 81e057a8d4bcde2d8cee628b8b02f90fbfb05954] --- compiler/src/dotty/tools/dotc/parsing/Scanners.scala | 1 + tests/pos/i22332.scala | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 tests/pos/i22332.scala diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index aadedde612f7..57a7ff1c4a9b 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -615,6 +615,7 @@ object Scanners { if nextWidth < lastWidth then currentRegion = topLevelRegion(nextWidth) else if !isLeadingInfixOperator(nextWidth) && !statCtdTokens.contains(lastToken) && lastToken != INDENT then currentRegion match + case _ if token == EOF => // no OUTDENT at EOF case r: Indented => insert(OUTDENT, offset) handleNewIndentWidth(r.enclosing, ir => diff --git a/tests/pos/i22332.scala b/tests/pos/i22332.scala new file mode 100644 index 000000000000..1b0b6a370329 --- /dev/null +++ b/tests/pos/i22332.scala @@ -0,0 +1,5 @@ + +object Foo: + val foo = 42 + // one space + \ No newline at end of file From 6b2ac6fffe1eba32130d802fa2d9e3bc790bbdad Mon Sep 17 00:00:00 2001 From: Matt Bovel Date: Thu, 30 Jan 2025 17:18:12 +0000 Subject: [PATCH 053/505] Fix inferredTypeEdits for symbols MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jędrzej Rochala [Cherry-picked f6234e768cd02be88e06b62bae50a2a67ce9f48f] --- .../dotty/tools/pc/InferredTypeProvider.scala | 22 +++-- .../tests/edit/InsertInferredTypeSuite.scala | 87 +++++++++++++++++++ 2 files changed, 101 insertions(+), 8 deletions(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/InferredTypeProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/InferredTypeProvider.scala index d8cdbcd8fe69..a0d726d5f382 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/InferredTypeProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/InferredTypeProvider.scala @@ -112,8 +112,8 @@ final class InferredTypeProvider( def imports: List[TextEdit] = printer.imports(autoImportsGen) - def printType(tpe: Type): String = - printer.tpe(tpe) + def printTypeAscription(tpe: Type, spaceBefore: Boolean = false): String = + (if spaceBefore then " : " else ": ") + printer.tpe(tpe) path.headOption match /* `val a = 1` or `var b = 2` @@ -124,7 +124,7 @@ final class InferredTypeProvider( * turns into * `.map((a: Int) => a + a)` */ - case Some(vl @ ValDef(sym, tpt, rhs)) => + case Some(vl @ ValDef(name, tpt, rhs)) => val isParam = path match case head :: next :: _ if next.symbol.isAnonymousFunction => true case head :: (b @ Block(stats, expr)) :: next :: _ @@ -136,9 +136,11 @@ final class InferredTypeProvider( val endPos = findNamePos(sourceText, vl, keywordOffset).endPos.toLsp adjustOpt.foreach(adjust => endPos.setEnd(adjust.adjustedEndPos)) + val spaceBefore = name.isOperatorName + new TextEdit( endPos, - ": " + printType(optDealias(tpt.typeOpt)) + { + printTypeAscription(optDealias(tpt.typeOpt), spaceBefore) + { if withParens then ")" else "" } ) @@ -197,7 +199,7 @@ final class InferredTypeProvider( * turns into * `def a[T](param : Int): Int = param` */ - case Some(df @ DefDef(name, _, tpt, rhs)) => + case Some(df @ DefDef(name, paramss, tpt, rhs)) => def typeNameEdit = /* NOTE: In Scala 3.1.3, `List((1,2)).map((<>,b) => ...)` * turns into `List((1,2)).map((:Inta,b) => ...)`, @@ -208,10 +210,12 @@ final class InferredTypeProvider( if tpt.endPos.end > df.namePos.end then tpt.endPos.toLsp else df.namePos.endPos.toLsp + val spaceBefore = name.isOperatorName && paramss.isEmpty + adjustOpt.foreach(adjust => end.setEnd(adjust.adjustedEndPos)) new TextEdit( end, - ": " + printType(optDealias(tpt.typeOpt)) + printTypeAscription(optDealias(tpt.typeOpt), spaceBefore) ) end typeNameEdit @@ -239,9 +243,10 @@ final class InferredTypeProvider( */ case Some(bind @ Bind(name, body)) => def baseEdit(withParens: Boolean) = + val spaceBefore = name.isOperatorName new TextEdit( bind.endPos.toLsp, - ": " + printType(optDealias(body.typeOpt)) + { + printTypeAscription(optDealias(body.typeOpt), spaceBefore) + { if withParens then ")" else "" } ) @@ -272,9 +277,10 @@ final class InferredTypeProvider( * `for(t: Int <- 0 to 10)` */ case Some(i @ Ident(name)) => + val spaceBefore = name.isOperatorName val typeNameEdit = new TextEdit( i.endPos.toLsp, - ": " + printType(optDealias(i.typeOpt.widen)) + printTypeAscription(optDealias(i.typeOpt.widen), spaceBefore) ) typeNameEdit :: imports diff --git a/presentation-compiler/test/dotty/tools/pc/tests/edit/InsertInferredTypeSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/edit/InsertInferredTypeSuite.scala index a96dd78be138..c1a84d6abb79 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/edit/InsertInferredTypeSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/edit/InsertInferredTypeSuite.scala @@ -883,6 +883,93 @@ class InsertInferredTypeSuite extends BaseCodeActionSuite: |""".stripMargin ) + @Test def `operator-val` = + checkEdit( + """|object A { + | val <> = 1 + |} + |""".stripMargin, + """|object A { + | val ! : Int = 1 + |} + |""".stripMargin + ) + + @Test def `operator-def` = + checkEdit( + """|object A { + | def <> = 1 + |} + |""".stripMargin, + """|object A { + | def ! : Int = 1 + |} + |""".stripMargin + ) + + @Test def `operator-def-param` = + checkEdit( + """|object A { + | def <>[T] = 1 + |} + |""".stripMargin, + """|object A { + | def ![T]: Int = 1 + |} + |""".stripMargin + ) + + @Test def `operator-def-type-param` = + checkEdit( + """|object A { + | def <>(x: Int) = 1 + |} + |""".stripMargin, + """|object A { + | def !(x: Int): Int = 1 + |} + |""".stripMargin + ) + + @Test def `operator-for` = + checkEdit( + """|object A { + | def foo = for(<> <- List(1)) yield ! + |} + |""".stripMargin, + """|object A { + | def foo = for(! : Int <- List(1)) yield ! + |} + |""".stripMargin + ) + @Test def `operator-lambda` = + checkEdit( + """|object A { + | val foo: Int => Int = (<>) => ! + 1 + |} + |""".stripMargin, + """|object A { + | val foo: Int => Int = (! : Int) => ! + 1 + |} + |""".stripMargin + ) + + @Test def `operator-ident` = + checkEdit( + """|object A { + | def foo = + | val ! = 1 + | <> + |} + |""".stripMargin, + """|object A { + | def foo = + | val ! = 1 + | ! : Int + |} + |""".stripMargin + ) + def checkEdit( original: String, expected: String From 1a9e6e460d95fc8951efa4fac8547be44b1fbc20 Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Fri, 31 Jan 2025 11:23:13 +0100 Subject: [PATCH 054/505] Remove DRI from Scaladoc warnings (#22330) partial fix for #20028 [Cherry-picked f88f92ea5b491f118b925edf427066446f9e48ff] --- scaladoc/src/dotty/tools/scaladoc/tasty/TypesSupport.scala | 4 ++-- .../src/dotty/tools/scaladoc/tasty/comments/Comments.scala | 2 +- .../dotty/tools/scaladoc/tasty/comments/MemberLookup.scala | 6 +++--- .../dotty/tools/scaladoc/tasty/comments/wiki/Entities.scala | 3 +-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/TypesSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/TypesSupport.scala index 35cf1cb6eec3..774e775f4e53 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/TypesSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/TypesSupport.scala @@ -75,7 +75,7 @@ trait TypesSupport: else inner(tpe) ++ plain(".").l ++ suffix case tpe => inner(tpe) - // TODO #23 add support for all types signatures that makes sense + // TODO #23 add support for all types signatures that make sense private def inner( using Quotes, )( @@ -87,7 +87,7 @@ trait TypesSupport: ): SSignature = import reflect._ def noSupported(name: String): SSignature = - println(s"WARN: Unsupported type: $name: ${tp.show}") + report.warning(s"Unsupported type: $name: ${tp.show}") plain(s"Unsupported[$name]").l tp match case OrType(left, right) => diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala index ff4405d3ec71..44a1c3630a5f 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala @@ -112,7 +112,7 @@ abstract class MarkupConversion[T](val repr: Repr)(using dctx: DocContext) { case None => sym.dri DocLink.ToDRI(dri, targetText) case None => - val txt = s"No DRI found for query" + val txt = s"Couldn't resolve a member for the given link query" val msg = s"$txt: $queryStr" if (!summon[DocContext].args.noLinkWarnings) then diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/MemberLookup.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/MemberLookup.scala index b2c4e1bdcac4..303722f8b2df 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/MemberLookup.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/MemberLookup.scala @@ -31,8 +31,8 @@ trait MemberLookup { def nearestPackage(sym: Symbol): Symbol = if sym.flags.is(Flags.Package) then sym else nearestPackage(sym.owner) - def nearestMembered(sym: Symbol): Symbol = - if sym.isClassDef || sym.flags.is(Flags.Package) then sym else nearestMembered(sym.owner) + def nearestMember(sym: Symbol): Symbol = + if sym.isClassDef || sym.flags.is(Flags.Package) then sym else nearestMember(sym.owner) val res: Option[(Symbol, String, Option[Symbol])] = { def toplevelLookup(querystrings: List[String]) = @@ -43,7 +43,7 @@ trait MemberLookup { ownerOpt match { case Some(owner) => - val nearest = nearestMembered(owner) + val nearest = nearestMember(owner) val nearestCls = nearestClass(owner) val nearestPkg = nearestPackage(owner) def relativeLookup(querystrings: List[String], owner: Symbol): Option[(Symbol, Option[Symbol])] = { diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/wiki/Entities.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/wiki/Entities.scala index f11e8095afe7..86e7298226ea 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/wiki/Entities.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/wiki/Entities.scala @@ -5,8 +5,7 @@ import scala.collection.{Seq => _, _} // import representations._ /** A body of text. A comment has a single body, which is composed of - * at least one block. Inside every body is exactly one summary (see - * [[scala.tools.nsc.doc.model.comment.Summary]]). */ + * at least one block. Inside every body is exactly one summary. */ final case class Body(blocks: Seq[Block]) { /** The summary text of the comment body. */ From 644099390a6957bec0ee62dacbbae3e012a6668a Mon Sep 17 00:00:00 2001 From: Joel Wilsson Date: Fri, 31 Jan 2025 22:42:33 +0100 Subject: [PATCH 055/505] Handle type aliases in contextFunctionResultTypeAfter (#21517) Closes #21433 --- .../dotty/tools/dotc/transform/ContextFunctionResults.scala | 2 +- tests/pos/i21433.scala | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 tests/pos/i21433.scala diff --git a/compiler/src/dotty/tools/dotc/transform/ContextFunctionResults.scala b/compiler/src/dotty/tools/dotc/transform/ContextFunctionResults.scala index 0bb54f8c9345..463bb68718ef 100644 --- a/compiler/src/dotty/tools/dotc/transform/ContextFunctionResults.scala +++ b/compiler/src/dotty/tools/dotc/transform/ContextFunctionResults.scala @@ -104,7 +104,7 @@ object ContextFunctionResults: def contextFunctionResultTypeAfter(meth: Symbol, depth: Int)(using Context) = def recur(tp: Type, n: Int): Type = if n == 0 then tp - else tp match + else tp.dealias match case defn.ContextFunctionType(_, resTpe) => recur(resTpe, n - 1) recur(meth.info.finalResultType, depth) diff --git a/tests/pos/i21433.scala b/tests/pos/i21433.scala new file mode 100644 index 000000000000..0efc4ac197ae --- /dev/null +++ b/tests/pos/i21433.scala @@ -0,0 +1,6 @@ +trait A[T]: + type R = T ?=> Unit + def f: R = () + +class B extends A[Int]: + override def f: R = () From e2ee55f095b9c1cea107f0a9e38b30ff2495313e Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Mon, 21 Apr 2025 13:54:29 +0200 Subject: [PATCH 056/505] Handle type aliases in contextFunctionResultTypeAfter (#21517) Closes #21433 [Cherry-picked 590691b09bb8554dd312a4e942f91dcd43ba6b44][modified] From 80fdbb882a7dce7f5bf1c8f8924154dba3c58dab Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Fri, 31 Jan 2025 14:18:56 +0000 Subject: [PATCH 057/505] Avoid inf recursion in provablyDisjointClasses --- tests/pos/i22266.scala | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/pos/i22266.scala diff --git a/tests/pos/i22266.scala b/tests/pos/i22266.scala new file mode 100644 index 000000000000..2ecdf9492a93 --- /dev/null +++ b/tests/pos/i22266.scala @@ -0,0 +1,22 @@ +sealed trait NonPolygon +sealed trait Polygon + +sealed trait SymmetryAspect +sealed trait RotationalSymmetry extends SymmetryAspect +sealed trait MaybeRotationalSymmetry extends SymmetryAspect + +enum Shape: + case Circle extends Shape with NonPolygon with RotationalSymmetry + case Triangle extends Shape with Polygon with MaybeRotationalSymmetry + case Square extends Shape with Polygon with RotationalSymmetry + +object Shape: + + def hasPolygon( + rotationalSyms: Vector[Shape & RotationalSymmetry], + maybeSyms: Vector[Shape & MaybeRotationalSymmetry] + ): Boolean = + val all = rotationalSyms.concat(maybeSyms) + all.exists: + case _: Polygon => true + case _ => false From 0adb4871211b70a87e11022047c4d427a2b36ad8 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Mon, 21 Apr 2025 14:10:23 +0200 Subject: [PATCH 058/505] Avoid inf recursion in provablyDisjointClasses [Cherry-picked 3cd94b4049d84d32464d695c753e1b1770a34c89][modified] From 596c11fa7a1eb2f3d7fb61d81348ec7502a7dab6 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Fri, 31 Jan 2025 15:19:02 +0000 Subject: [PATCH 059/505] Avoid early widening enum val symbols in provablyDisjointClasses --- tests/pos/i22266.unenum.scala | 22 ++++++++++++++++++++++ tests/warn/ext-override.scala | 2 +- tests/warn/i21860.unenum.scala | 2 +- 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 tests/pos/i22266.unenum.scala diff --git a/tests/pos/i22266.unenum.scala b/tests/pos/i22266.unenum.scala new file mode 100644 index 000000000000..e7529b7edabe --- /dev/null +++ b/tests/pos/i22266.unenum.scala @@ -0,0 +1,22 @@ +sealed trait NonPolygon +sealed trait Polygon + +sealed trait SymmetryAspect +sealed trait RotationalSymmetry extends SymmetryAspect +sealed trait MaybeRotationalSymmetry extends SymmetryAspect + +sealed abstract class Shape + +object Shape: + case object Circle extends Shape with NonPolygon with RotationalSymmetry + case object Triangle extends Shape with Polygon with MaybeRotationalSymmetry + case object Square extends Shape with Polygon with RotationalSymmetry + + def hasPolygon( + rotationalSyms: Vector[Shape & RotationalSymmetry], + maybeSyms: Vector[Shape & MaybeRotationalSymmetry] + ): Boolean = + val all = rotationalSyms.concat(maybeSyms) + all.exists: + case _: Polygon => true + case _ => false diff --git a/tests/warn/ext-override.scala b/tests/warn/ext-override.scala index 7c082695cbaa..d08439e13c9a 100644 --- a/tests/warn/ext-override.scala +++ b/tests/warn/ext-override.scala @@ -7,6 +7,6 @@ trait Foo[T]: class Bla: def hi: String = "hi" object Bla: - given Foo[Bla]: + given Foo[Bla] with extension (x: Bla) def hi: String = x.hi diff --git a/tests/warn/i21860.unenum.scala b/tests/warn/i21860.unenum.scala index 7335e1b6851d..e4b282e35e76 100644 --- a/tests/warn/i21860.unenum.scala +++ b/tests/warn/i21860.unenum.scala @@ -3,7 +3,7 @@ sealed trait Corners { self: Figure => } sealed abstract class Shape extends Figure object Shape: - case object Triange extends Shape with Corners + case object Triangle extends Shape with Corners case object Square extends Shape with Corners case object Circle extends Shape case object Ellipsis extends Shape From 6b2eca34c1978cc9fa53ead7c8f4f868148a5455 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Mon, 21 Apr 2025 14:14:44 +0200 Subject: [PATCH 060/505] Avoid early widening enum val symbols in provablyDisjointClasses [Cherry-picked 04f6fc3893404bfc8c87395d2daa5601b7672fe9][modified] From 04e9c0a4f1dfbcecec15570b91604d58560f8d98 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Mon, 3 Feb 2025 11:40:29 +0000 Subject: [PATCH 061/505] Document enum value changes in provablyDisjointClasses --- compiler/src/dotty/tools/dotc/core/TypeComparer.scala | 6 +++--- docs/_spec/03-types.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 5e0d9a98aa74..48274e0561ef 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -2772,11 +2772,11 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling * * 1. Single inheritance of classes * 2. Final classes cannot be extended - * 3. ConstantTypes with distinct values are non intersecting - * 4. TermRefs with distinct values are non intersecting + * 3. ConstantTypes with distinct values are non-intersecting + * 4. TermRefs with distinct values are non-intersecting * 5. There is no value of type Nothing * - * Note on soundness: the correctness of match types relies on on the + * Note on soundness: the correctness of match types relies on the * property that in all possible contexts, the same match type expression * is either stuck or reduces to the same case. */ diff --git a/docs/_spec/03-types.md b/docs/_spec/03-types.md index 4b1293258495..5d4e205aace9 100644 --- a/docs/_spec/03-types.md +++ b/docs/_spec/03-types.md @@ -1071,7 +1071,7 @@ The following properties hold about ´⌈X⌉´ (we have paper proofs for those) The "lower-bound rule" states that ´S <: T´ if ´T = q.X´ and ´q.X´ is a non-class type designator and ´S <: L´ where ´L´ is the lower bound of the underlying type definition of ´q.X´". That rule is known to break transitivy of subtyping in Scala already. -Second, we define the relation ´⋔´ on *classes* (including traits and hidden classes of objects) as: +Second, we define the relation ´⋔´ on *classes* (including traits, hidden classes of objects, and enum terms) as: - ´C ⋔ D´ if `´C ∉´ baseClasses´(D)´` and ´D´ is `final` - ´C ⋔ D´ if `´D ∉´ baseClasses´(C)´` and ´C´ is `final` From c9fe273dc603e343133997ff5a67c5a0bc365955 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Mon, 21 Apr 2025 14:15:07 +0200 Subject: [PATCH 062/505] Document enum value changes in provablyDisjointClasses [Cherry-picked 4cd2a97a1c74a1eb3408e128fa4166eb1d0899f7][modified] From ddea7c73cc35e9ec6aa3eb1870941eaa8e602360 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Mon, 3 Feb 2025 16:24:56 -0800 Subject: [PATCH 063/505] Don't warn retainedBody --- .../dotty/tools/dotc/transform/CheckUnused.scala | 3 ++- tests/warn/t22507.scala | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/warn/t22507.scala diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index 29fef0843902..a454c59eea7b 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -8,7 +8,7 @@ import dotty.tools.dotc.core.Contexts.* import dotty.tools.dotc.core.Flags.* import dotty.tools.dotc.core.Names.{Name, SimpleName, DerivedName, TermName, termName} import dotty.tools.dotc.core.NameOps.{isAnonymousFunctionName, isReplWrapperName, isContextFunction} -import dotty.tools.dotc.core.NameKinds.{ContextBoundParamName, ContextFunctionParamName, WildcardParamName} +import dotty.tools.dotc.core.NameKinds.{BodyRetainerName, ContextBoundParamName, ContextFunctionParamName, WildcardParamName} import dotty.tools.dotc.core.StdNames.nme import dotty.tools.dotc.core.Symbols.{ClassSymbol, NoSymbol, Symbol, defn, isDeprecated, requiredClass, requiredModule} import dotty.tools.dotc.core.Types.* @@ -502,6 +502,7 @@ object CheckUnused: if ctx.settings.WunusedHas.privates && !sym.isPrimaryConstructor && sym.is(Private, butNot = SelfName | Synthetic | CaseAccessor) + && !sym.name.is(BodyRetainerName) && !sym.isSerializationSupport && !(sym.is(Mutable) && sym.isSetter && sym.owner.is(Trait)) // tracks sym.underlyingSymbol sibling getter then diff --git a/tests/warn/t22507.scala b/tests/warn/t22507.scala new file mode 100644 index 000000000000..76ae9a2b9a8b --- /dev/null +++ b/tests/warn/t22507.scala @@ -0,0 +1,14 @@ + +//> using options -Werror -Wunused:privates + +case class BinaryFen(value: Array[Byte]) extends AnyVal: + + def read: Unit = + val reader = new Iterator[Byte]: + val inner = value.iterator + override inline def hasNext: Boolean = inner.hasNext // nowarn + override inline def next: Byte = if hasNext then inner.next else 0.toByte // nowarn + + if reader.hasNext then + val b: Byte = reader.next + println(b) From 7a5415b6b989a023340687e4fcd9fd78d35fcb63 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Mon, 21 Apr 2025 14:16:31 +0200 Subject: [PATCH 064/505] Don't warn retainedBody [Cherry-picked 8d3954f8095a6705c0aaaf103245f071943c48a3][modified] From 221c36922f24c1d7fdaf6971caa2208e2925eef0 Mon Sep 17 00:00:00 2001 From: kasiaMarek Date: Fri, 31 Jan 2025 17:17:42 +0100 Subject: [PATCH 065/505] chore: update mtags to `1.5.1` [Cherry-picked 19690b4a1bf13e19da3441f2a1cad52ad4d5dfc2] --- .../dotty/tools/pc/PcInlayHintsProvider.scala | 2 +- .../tools/pc/ScalaPresentationCompiler.scala | 109 ++++++++++-------- project/Build.scala | 2 +- 3 files changed, 63 insertions(+), 50 deletions(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala index 4b1b3f5fe7ba..cf4929dfc91d 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala @@ -57,7 +57,7 @@ class PcInlayHintsProvider( .headOption .getOrElse(unit.tpdTree) .enclosedChildren(pos.span) - .flatMap(tpdTree => deepFolder(InlayHints.empty, tpdTree).result()) + .flatMap(tpdTree => deepFolder(InlayHints.empty(params.uri()), tpdTree).result()) private def adjustPos(pos: SourcePosition): SourcePosition = pos.adjust(text)._1 diff --git a/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala b/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala index a44c16ecc748..dc53525480c3 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala @@ -16,6 +16,7 @@ import scala.language.unsafeNulls import scala.meta.internal.metals.CompilerVirtualFileParams import scala.meta.internal.metals.EmptyCancelToken import scala.meta.internal.metals.EmptyReportContext +import scala.meta.internal.metals.PcQueryContext import scala.meta.internal.metals.ReportContext import scala.meta.internal.metals.ReportLevel import scala.meta.internal.metals.StdReportContext @@ -143,18 +144,18 @@ case class ScalaPresentationCompiler( override def semanticTokens( params: VirtualFileParams ): CompletableFuture[ju.List[Node]] = - compilerAccess.withInterruptableCompiler(Some(params))( + compilerAccess.withInterruptableCompiler( new ju.ArrayList[Node](), params.token() ) { access => val driver = access.compiler() new PcSemanticTokensProvider(driver, params).provide().asJava - } + }(params.toQueryContext) override def inlayHints( params: InlayHintsParams ): ju.concurrent.CompletableFuture[ju.List[l.InlayHint]] = - compilerAccess.withInterruptableCompiler(Some(params))( + compilerAccess.withInterruptableCompiler( new ju.ArrayList[l.InlayHint](), params.token(), ) { access => @@ -162,7 +163,7 @@ case class ScalaPresentationCompiler( new PcInlayHintsProvider(driver, params, search) .provide() .asJava - } + }(params.toQueryContext) override def getTasty( targetUri: URI, @@ -173,7 +174,7 @@ case class ScalaPresentationCompiler( } def complete(params: OffsetParams): CompletableFuture[l.CompletionList] = - compilerAccess.withInterruptableCompiler(Some(params))( + compilerAccess.withInterruptableCompiler( EmptyCompletionList(), params.token() ) { access => @@ -188,44 +189,43 @@ case class ScalaPresentationCompiler( folderPath, completionItemPriority ).completions() - - } + }(params.toQueryContext) def definition(params: OffsetParams): CompletableFuture[DefinitionResult] = - compilerAccess.withInterruptableCompiler(Some(params))( + compilerAccess.withInterruptableCompiler( DefinitionResultImpl.empty, params.token() ) { access => val driver = access.compiler() PcDefinitionProvider(driver, params, search).definitions() - } + }(params.toQueryContext) override def typeDefinition( params: OffsetParams ): CompletableFuture[DefinitionResult] = - compilerAccess.withInterruptableCompiler(Some(params))( + compilerAccess.withInterruptableCompiler( DefinitionResultImpl.empty, params.token() ) { access => val driver = access.compiler() PcDefinitionProvider(driver, params, search).typeDefinitions() - } + }(params.toQueryContext) def documentHighlight( params: OffsetParams ): CompletableFuture[ju.List[DocumentHighlight]] = - compilerAccess.withInterruptableCompiler(Some(params))( + compilerAccess.withInterruptableCompiler( List.empty[DocumentHighlight].asJava, params.token() ) { access => val driver = access.compiler() PcDocumentHighlightProvider(driver, params).highlights.asJava - } + }(params.toQueryContext) override def references( params: ReferencesRequest ): CompletableFuture[ju.List[ReferencesResult]] = - compilerAccess.withNonInterruptableCompiler(Some(params.file()))( + compilerAccess.withNonInterruptableCompiler( List.empty[ReferencesResult].asJava, params.file().token, ) { access => @@ -233,16 +233,16 @@ case class ScalaPresentationCompiler( PcReferencesProvider(driver, params) .references() .asJava - } + }(params.file().toQueryContext) def inferExpectedType(params: OffsetParams): CompletableFuture[ju.Optional[String]] = - compilerAccess.withInterruptableCompiler(Some(params))( + compilerAccess.withInterruptableCompiler( Optional.empty(), params.token, ) { access => val driver = access.compiler() new InferExpectedType(search, driver, params).infer().asJava - } + }(params.toQueryContext) def shutdown(): Unit = compilerAccess.shutdown() @@ -257,8 +257,6 @@ case class ScalaPresentationCompiler( symbol: String ): CompletableFuture[Optional[IPcSymbolInformation]] = compilerAccess.withNonInterruptableCompiler[Optional[IPcSymbolInformation]]( - None - )( Optional.empty(), EmptyCancelToken, ) { access => @@ -266,27 +264,27 @@ case class ScalaPresentationCompiler( .info(symbol) .map(_.asJava) .asJava - } + }(emptyQueryContext) def semanticdbTextDocument( filename: URI, code: String ): CompletableFuture[Array[Byte]] = val virtualFile = CompilerVirtualFileParams(filename, code) - compilerAccess.withNonInterruptableCompiler(Some(virtualFile))( + compilerAccess.withNonInterruptableCompiler( Array.empty[Byte], EmptyCancelToken ) { access => val driver = access.compiler() val provider = SemanticdbTextDocumentProvider(driver, folderPath) provider.textDocument(filename, code) - } + }(virtualFile.toQueryContext) def completionItemResolve( item: l.CompletionItem, symbol: String ): CompletableFuture[l.CompletionItem] = - compilerAccess.withNonInterruptableCompiler(None)( + compilerAccess.withNonInterruptableCompiler( item, EmptyCancelToken ) { access => @@ -294,7 +292,7 @@ case class ScalaPresentationCompiler( CompletionItemResolver.resolve(item, symbol, search, config)(using driver.currentCtx ) - } + }(emptyQueryContext) def autoImports( name: String, @@ -303,7 +301,7 @@ case class ScalaPresentationCompiler( ): CompletableFuture[ ju.List[scala.meta.pc.AutoImportsResult] ] = - compilerAccess.withNonInterruptableCompiler(Some(params))( + compilerAccess.withNonInterruptableCompiler( List.empty[scala.meta.pc.AutoImportsResult].asJava, params.token() ) { access => @@ -318,13 +316,13 @@ case class ScalaPresentationCompiler( ) .autoImports(isExtension) .asJava - } + }(params.toQueryContext) def implementAbstractMembers( params: OffsetParams ): CompletableFuture[ju.List[l.TextEdit]] = val empty: ju.List[l.TextEdit] = new ju.ArrayList[l.TextEdit]() - compilerAccess.withNonInterruptableCompiler(Some(params))( + compilerAccess.withNonInterruptableCompiler( empty, params.token() ) { pc => @@ -335,31 +333,31 @@ case class ScalaPresentationCompiler( search, config ) - } + }(params.toQueryContext) end implementAbstractMembers override def insertInferredType( params: OffsetParams ): CompletableFuture[ju.List[l.TextEdit]] = val empty: ju.List[l.TextEdit] = new ju.ArrayList[l.TextEdit]() - compilerAccess.withNonInterruptableCompiler(Some(params))( + compilerAccess.withNonInterruptableCompiler( empty, params.token() ) { pc => new InferredTypeProvider(params, pc.compiler(), config, search) .inferredTypeEdits() .asJava - } + }(params.toQueryContext) override def inlineValue( params: OffsetParams ): CompletableFuture[ju.List[l.TextEdit]] = val empty: Either[String, List[l.TextEdit]] = Right(List()) (compilerAccess - .withInterruptableCompiler(Some(params))(empty, params.token()) { pc => + .withInterruptableCompiler(empty, params.token()) { pc => new PcInlineValueProviderImpl(pc.compiler(), params) .getInlineTextEdits() - }) + }(params.toQueryContext)) .thenApply { case Right(edits: List[TextEdit]) => edits.asJava case Left(error: String) => throw new DisplayableException(error) @@ -371,7 +369,7 @@ case class ScalaPresentationCompiler( extractionPos: OffsetParams ): CompletableFuture[ju.List[l.TextEdit]] = val empty: ju.List[l.TextEdit] = new ju.ArrayList[l.TextEdit]() - compilerAccess.withInterruptableCompiler(Some(range))(empty, range.token()) { + compilerAccess.withInterruptableCompiler(empty, range.token()) { pc => new ExtractMethodProvider( range, @@ -382,7 +380,7 @@ case class ScalaPresentationCompiler( ) .extractMethod() .asJava - } + }(range.toQueryContext) end extractMethod override def convertToNamedArguments( @@ -397,13 +395,13 @@ case class ScalaPresentationCompiler( ): CompletableFuture[ju.List[l.TextEdit]] = val empty: Either[String, List[l.TextEdit]] = Right(List()) (compilerAccess - .withNonInterruptableCompiler(Some(params))(empty, params.token()) { pc => + .withNonInterruptableCompiler(empty, params.token()) { pc => new ConvertToNamedArgumentsProvider( pc.compiler(), params, argIndices ).convertToNamedArguments - }) + }(params.toQueryContext)) .thenApplyAsync { case Left(error: String) => throw new DisplayableException(error) case Right(edits: List[l.TextEdit]) => edits.asJava @@ -413,33 +411,33 @@ case class ScalaPresentationCompiler( params: ju.List[OffsetParams] ): CompletableFuture[ju.List[l.SelectionRange]] = CompletableFuture.completedFuture { - compilerAccess.withSharedCompiler(params.asScala.headOption)( + compilerAccess.withSharedCompiler( List.empty[l.SelectionRange].asJava ) { pc => new SelectionRangeProvider( pc.compiler(), params, ).selectionRange().asJava - } + }(params.asScala.headOption.map(_.toQueryContext).getOrElse(emptyQueryContext)) } end selectionRange def hover( params: OffsetParams ): CompletableFuture[ju.Optional[HoverSignature]] = - compilerAccess.withNonInterruptableCompiler(Some(params))( + compilerAccess.withNonInterruptableCompiler( ju.Optional.empty[HoverSignature](), params.token() ) { access => val driver = access.compiler() HoverProvider.hover(params, driver, search, config.hoverContentType()) - } + }(params.toQueryContext) end hover def prepareRename( params: OffsetParams ): CompletableFuture[ju.Optional[l.Range]] = - compilerAccess.withNonInterruptableCompiler(Some(params))( + compilerAccess.withNonInterruptableCompiler( Optional.empty[l.Range](), params.token() ) { access => @@ -447,19 +445,19 @@ case class ScalaPresentationCompiler( Optional.ofNullable( PcRenameProvider(driver, params, None).prepareRename().orNull ) - } + }(params.toQueryContext) def rename( params: OffsetParams, name: String ): CompletableFuture[ju.List[l.TextEdit]] = - compilerAccess.withNonInterruptableCompiler(Some(params))( + compilerAccess.withNonInterruptableCompiler( List[l.TextEdit]().asJava, params.token() ) { access => val driver = access.compiler() PcRenameProvider(driver, params, Some(name)).rename().asJava - } + }(params.toQueryContext) def newInstance( buildTargetIdentifier: String, @@ -473,13 +471,13 @@ case class ScalaPresentationCompiler( ) def signatureHelp(params: OffsetParams): CompletableFuture[l.SignatureHelp] = - compilerAccess.withNonInterruptableCompiler(Some(params))( + compilerAccess.withNonInterruptableCompiler( new l.SignatureHelp(), params.token() ) { access => val driver = access.compiler() SignatureHelpProvider.signatureHelp(driver, params, search) - } + }(params.toQueryContext) override def didChange( params: VirtualFileParams @@ -487,10 +485,10 @@ case class ScalaPresentationCompiler( CompletableFuture.completedFuture(Nil.asJava) override def didClose(uri: URI): Unit = - compilerAccess.withNonInterruptableCompiler(None)( + compilerAccess.withNonInterruptableCompiler( (), EmptyCancelToken - ) { access => access.compiler().close(uri) } + ) { access => access.compiler().close(uri) }(emptyQueryContext) override def withExecutorService( executorService: ExecutorService @@ -515,4 +513,19 @@ case class ScalaPresentationCompiler( override def isLoaded() = compilerAccess.isLoaded() + def additionalReportData() = + s"""|Scala version: $scalaVersion + |Classpath: + |${classpath + .map(path => s"$path [${if path.exists then "exists" else "missing"} ]") + .mkString(", ")} + |Options: + |${options.mkString(" ")} + |""".stripMargin + + extension (params: VirtualFileParams) + def toQueryContext = PcQueryContext(Some(params), additionalReportData) + + def emptyQueryContext = PcQueryContext(None, additionalReportData) + end ScalaPresentationCompiler diff --git a/project/Build.scala b/project/Build.scala index 82d9cb786811..2da2345e28fd 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -1236,7 +1236,7 @@ object Build { BuildInfoPlugin.buildInfoDefaultSettings lazy val presentationCompilerSettings = { - val mtagsVersion = "1.4.2" + val mtagsVersion = "1.5.1" Seq( libraryDependencies ++= Seq( "org.lz4" % "lz4-java" % "1.8.0", From cfaba1b6af1e0cbbcd024b54dff61c389e12ea39 Mon Sep 17 00:00:00 2001 From: kasiaMarek Date: Fri, 31 Jan 2025 17:48:31 +0100 Subject: [PATCH 066/505] improvement: look for definition in pc only for local symbols in the current tree [Cherry-picked 559edd49631715d3135000cfb183e292759ea9ae] --- .../dotty/tools/pc/PcDefinitionProvider.scala | 28 +++++++++++-------- .../tools/pc/tests/CompilerCachingSuite.scala | 14 ++++++---- .../dotty/tools/pc/utils/TestInlayHints.scala | 16 +++++------ 3 files changed, 34 insertions(+), 24 deletions(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/PcDefinitionProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/PcDefinitionProvider.scala index 7d8e4dfad081..8ff43ba07358 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/PcDefinitionProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/PcDefinitionProvider.scala @@ -1,5 +1,6 @@ package dotty.tools.pc +import java.net.URI import java.nio.file.Paths import java.util.ArrayList @@ -16,6 +17,7 @@ import dotty.tools.dotc.core.Contexts.Context import dotty.tools.dotc.core.Flags.{Exported, ModuleClass} import dotty.tools.dotc.core.Symbols.* import dotty.tools.dotc.interactive.Interactive +import dotty.tools.dotc.interactive.Interactive.Include import dotty.tools.dotc.interactive.InteractiveDriver import dotty.tools.dotc.util.SourceFile import dotty.tools.dotc.util.SourcePosition @@ -51,10 +53,10 @@ class PcDefinitionProvider( given ctx: Context = driver.localContext(params) val indexedContext = IndexedContext(ctx) val result = - if findTypeDef then findTypeDefinitions(path, pos, indexedContext) - else findDefinitions(path, pos, indexedContext) + if findTypeDef then findTypeDefinitions(path, pos, indexedContext, uri) + else findDefinitions(path, pos, indexedContext, uri) - if result.locations().nn.isEmpty() then fallbackToUntyped(pos)(using ctx) + if result.locations().nn.isEmpty() then fallbackToUntyped(pos, uri)(using ctx) else result end definitions @@ -70,24 +72,26 @@ class PcDefinitionProvider( * @param pos cursor position * @return definition result */ - private def fallbackToUntyped(pos: SourcePosition)( + private def fallbackToUntyped(pos: SourcePosition, uri: URI)( using ctx: Context ) = lazy val untpdPath = NavigateAST .untypedPath(pos.span) .collect { case t: untpd.Tree => t } - definitionsForSymbol(untpdPath.headOption.map(_.symbol).toList, pos) + definitionsForSymbol(untpdPath.headOption.map(_.symbol).toList, uri, pos) end fallbackToUntyped private def findDefinitions( path: List[Tree], pos: SourcePosition, - indexed: IndexedContext + indexed: IndexedContext, + uri: URI, ): DefinitionResult = import indexed.ctx definitionsForSymbol( MetalsInteractive.enclosingSymbols(path, pos, indexed), + uri, pos ) end findDefinitions @@ -95,7 +99,8 @@ class PcDefinitionProvider( private def findTypeDefinitions( path: List[Tree], pos: SourcePosition, - indexed: IndexedContext + indexed: IndexedContext, + uri: URI, ): DefinitionResult = import indexed.ctx val enclosing = path.expandRangeToEnclosingApply(pos) @@ -108,24 +113,25 @@ class PcDefinitionProvider( case Nil => path.headOption match case Some(value: Literal) => - definitionsForSymbol(List(value.typeOpt.widen.typeSymbol), pos) + definitionsForSymbol(List(value.typeOpt.widen.typeSymbol), uri, pos) case _ => DefinitionResultImpl.empty case _ => - definitionsForSymbol(typeSymbols, pos) + definitionsForSymbol(typeSymbols, uri, pos) end findTypeDefinitions private def definitionsForSymbol( symbols: List[Symbol], + uri: URI, pos: SourcePosition )(using ctx: Context): DefinitionResult = symbols match case symbols @ (sym :: other) => val isLocal = sym.source == pos.source if isLocal then + val include = Include.definitions | Include.local val (exportedDefs, otherDefs) = - Interactive.findDefinitions(List(sym), driver, false, false) - .filter(_.source == sym.source) + Interactive.findTreesMatching(driver.openedTrees(uri), include, sym) .partition(_.tree.symbol.is(Exported)) otherDefs.headOption.orElse(exportedDefs.headOption) match diff --git a/presentation-compiler/test/dotty/tools/pc/tests/CompilerCachingSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/CompilerCachingSuite.scala index 5e13c07b9e5f..b2d837e2ff50 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/CompilerCachingSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/CompilerCachingSuite.scala @@ -6,8 +6,10 @@ import dotty.tools.pc.ScalaPresentationCompiler import org.junit.{Before, Test} import scala.language.unsafeNulls -import scala.meta.internal.metals.EmptyCancelToken import scala.meta.internal.metals.CompilerOffsetParams +import scala.meta.internal.metals.EmptyCancelToken +import scala.meta.internal.metals.EmptyReportContext +import scala.meta.internal.metals.PcQueryContext import scala.meta.pc.OffsetParams import scala.concurrent.Future import scala.concurrent.Await @@ -26,20 +28,22 @@ class CompilerCachingSuite extends BasePCSuite: private def checkCompilationCount(expected: Int): Unit = presentationCompiler match case pc: ScalaPresentationCompiler => - val compilations = pc.compilerAccess.withNonInterruptableCompiler(None)(-1, EmptyCancelToken) { driver => + val compilations = pc.compilerAccess.withNonInterruptableCompiler(-1, EmptyCancelToken) { driver => driver.compiler().currentCtx.runId - }.get(timeout.length, timeout.unit) + }(emptyQueryContext).get(timeout.length, timeout.unit) assertEquals(expected, compilations, s"Expected $expected compilations but got $compilations") case _ => throw IllegalStateException("Presentation compiler should always be of type of ScalaPresentationCompiler") private def getContext(): Context = presentationCompiler match case pc: ScalaPresentationCompiler => - pc.compilerAccess.withNonInterruptableCompiler(None)(null, EmptyCancelToken) { driver => + pc.compilerAccess.withNonInterruptableCompiler(null, EmptyCancelToken) { driver => driver.compiler().currentCtx - }.get(timeout.length, timeout.unit) + }(emptyQueryContext).get(timeout.length, timeout.unit) case _ => throw IllegalStateException("Presentation compiler should always be of type of ScalaPresentationCompiler") + private def emptyQueryContext = PcQueryContext(None, () => "")(using EmptyReportContext) + @Before def beforeEach: Unit = presentationCompiler.restart() diff --git a/presentation-compiler/test/dotty/tools/pc/utils/TestInlayHints.scala b/presentation-compiler/test/dotty/tools/pc/utils/TestInlayHints.scala index b9d3fd411dcc..5fb38ad88e19 100644 --- a/presentation-compiler/test/dotty/tools/pc/utils/TestInlayHints.scala +++ b/presentation-compiler/test/dotty/tools/pc/utils/TestInlayHints.scala @@ -3,8 +3,10 @@ package dotty.tools.pc.utils import scala.collection.mutable.ListBuffer import scala.meta.internal.jdk.CollectionConverters._ +import scala.meta.internal.pc.InlayHints import dotty.tools.pc.utils.InteractiveEnrichments.* +import com.google.gson.JsonElement import org.eclipse.lsp4j.InlayHint import org.eclipse.lsp4j.TextEdit import org.eclipse.{lsp4j => l} @@ -31,7 +33,7 @@ object TestInlayHints { case Right(labelParts) => labelParts.asScala.map(_.getValue()).toList } val data = - inlayHint.getData().asInstanceOf[Array[Any]] + InlayHints.fromData(inlayHint.getData().asInstanceOf[JsonElement])._2 buffer += "/*" labels.zip(data).foreach { case (label, data) => buffer += label.nn @@ -41,15 +43,13 @@ object TestInlayHints { buffer.toList.mkString } - private def readData(data: Any): List[String] = { - data match { - case data: String if data.isEmpty => Nil - case data: String => List("<<", data, ">>") - case data: l.Position => + private def readData(data: Either[String, l.Position]): List[String] = + data match + case Left("") => Nil + case Left(data) => List("<<", data, ">>") + case Right(data) => val str = s"(${data.getLine()}:${data.getCharacter()})" List("<<", str, ">>") - } - } def applyInlayHints(text: String, inlayHints: List[InlayHint]): String = { val textEdits = inlayHints.map { hint => From dd8caef05cef91c7e60c8c5fa3b2d2d03bda70ac Mon Sep 17 00:00:00 2001 From: Hamza Remmal Date: Tue, 4 Feb 2025 21:04:54 +0100 Subject: [PATCH 067/505] fix: align erasure of Array[Nothing] and Array[Null] with Scala 2 [Cherry-picked c197afb0d7b2b17a081f7742d8f20118815447d4] --- .../src/dotty/tools/dotc/core/TypeErasure.scala | 14 ++++++++------ sbt-test/scala2-compat/erasure/dottyApp/Api.scala | 6 ++++++ sbt-test/scala2-compat/erasure/dottyApp/Main.scala | 4 ++++ sbt-test/scala2-compat/erasure/scala2Lib/Api.scala | 6 ++++++ 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 17ddc93a10f2..85fcaae350dd 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -597,8 +597,8 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst * will be returned. * * In all other situations, |T| will be computed as follow: - * - For a refined type scala.Array+[T]: - * - if T is Nothing or Null, []Object + * - For a refined type scala.Array[T]: + * - {Scala 2} if T is Nothing or Null, []Object * - otherwise, if T <: Object, []|T| * - otherwise, if T is a type parameter coming from Java, []Object * - otherwise, Object @@ -781,10 +781,12 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst val defn.ArrayOf(elemtp) = tp: @unchecked if (isGenericArrayElement(elemtp, isScala2 = sourceLanguage.isScala2)) defn.ObjectType else - try - val eElem = erasureFn(sourceLanguage, semiEraseVCs = false, isConstructor, isSymbol, inSigName)(elemtp) - if eElem.isInstanceOf[WildcardType] then WildcardType - else JavaArrayType(eElem) + try + if sourceLanguage.isScala2 && (elemtp.isNullType || elemtp.isNothingType) then + JavaArrayType(defn.ObjectType) + else erasureFn(sourceLanguage, semiEraseVCs = false, isConstructor, isSymbol, inSigName)(elemtp) match + case _: WildcardType => WildcardType + case elem => JavaArrayType(elem) catch case ex: Throwable => handleRecursive("erase array type", tp.show, ex) } diff --git a/sbt-test/scala2-compat/erasure/dottyApp/Api.scala b/sbt-test/scala2-compat/erasure/dottyApp/Api.scala index 7ce908820390..25fc4f6a0692 100644 --- a/sbt-test/scala2-compat/erasure/dottyApp/Api.scala +++ b/sbt-test/scala2-compat/erasure/dottyApp/Api.scala @@ -195,4 +195,10 @@ class Z { def objectARRAY_88(x: Array[Any]): Unit = {} def objectARRAY_89(x: Array[AnyRef]): Unit = {} def objectARRAY_90(x: Array[AnyVal]): Unit = {} + + def objectARRAY_91(x: Array[Nothing]): Unit = {} + def objectARRAY_92(x: Array[Null]): Unit = {} + def objectARRAY_93(x: Array[_ <: Nothing]): Unit = {} + def objectARRAY_94(x: Array[_ <: Null]): Unit = {} + } diff --git a/sbt-test/scala2-compat/erasure/dottyApp/Main.scala b/sbt-test/scala2-compat/erasure/dottyApp/Main.scala index be2c6c737316..a0f2df0c4e8c 100644 --- a/sbt-test/scala2-compat/erasure/dottyApp/Main.scala +++ b/sbt-test/scala2-compat/erasure/dottyApp/Main.scala @@ -101,6 +101,10 @@ object Main { z.objectARRAY_88(dummy) z.objectARRAY_89(dummy) z.objectARRAY_90(dummy) + z.objectARRAY_91(dummy) + z.objectARRAY_92(dummy) + z.objectARRAY_93(dummy) + z.objectARRAY_94(dummy) val methods = classOf[scala2Lib.Z].getDeclaredMethods.toList ++ classOf[dottyApp.Z].getDeclaredMethods.toList methods.foreach { m => diff --git a/sbt-test/scala2-compat/erasure/scala2Lib/Api.scala b/sbt-test/scala2-compat/erasure/scala2Lib/Api.scala index 2578f0556ecb..14a96b8e4004 100644 --- a/sbt-test/scala2-compat/erasure/scala2Lib/Api.scala +++ b/sbt-test/scala2-compat/erasure/scala2Lib/Api.scala @@ -186,4 +186,10 @@ class Z { def objectARRAY_88(x: Array[Any]): Unit = {} def objectARRAY_89(x: Array[AnyRef]): Unit = {} def objectARRAY_90(x: Array[AnyVal]): Unit = {} + + def objectARRAY_91(x: Array[Nothing]): Unit = {} + def objectARRAY_92(x: Array[Null]): Unit = {} + def objectARRAY_93(x: Array[_ <: Nothing]): Unit = {} + def objectARRAY_94(x: Array[_ <: Null]): Unit = {} + } From bf2884dae49ff0a3b0c8b309817ea3a2f96909b5 Mon Sep 17 00:00:00 2001 From: Hamza Remmal Date: Wed, 5 Feb 2025 14:57:01 +0100 Subject: [PATCH 068/505] fix: reliably run sbt-test scala2-compat/erasure [Cherry-picked da06de5a445892a06a7f661b3ce715a94cd13e5e] --- sbt-test/scala2-compat/erasure/build.sbt | 2 ++ sbt-test/scala2-compat/erasure/dottyApp/Api.scala | 8 ++++---- sbt-test/scala2-compat/erasure/dottyApp/Main.scala | 8 ++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/sbt-test/scala2-compat/erasure/build.sbt b/sbt-test/scala2-compat/erasure/build.sbt index 694101e79388..f705299f549d 100644 --- a/sbt-test/scala2-compat/erasure/build.sbt +++ b/sbt-test/scala2-compat/erasure/build.sbt @@ -1,3 +1,5 @@ +ThisBuild / fork := true + lazy val scala2Lib = project.in(file("scala2Lib")) .settings( scalaVersion := sys.props("plugin.scala2Version") diff --git a/sbt-test/scala2-compat/erasure/dottyApp/Api.scala b/sbt-test/scala2-compat/erasure/dottyApp/Api.scala index 25fc4f6a0692..154e5027d2d1 100644 --- a/sbt-test/scala2-compat/erasure/dottyApp/Api.scala +++ b/sbt-test/scala2-compat/erasure/dottyApp/Api.scala @@ -196,9 +196,9 @@ class Z { def objectARRAY_89(x: Array[AnyRef]): Unit = {} def objectARRAY_90(x: Array[AnyVal]): Unit = {} - def objectARRAY_91(x: Array[Nothing]): Unit = {} - def objectARRAY_92(x: Array[Null]): Unit = {} - def objectARRAY_93(x: Array[_ <: Nothing]): Unit = {} - def objectARRAY_94(x: Array[_ <: Null]): Unit = {} + def nothing$ARRAY_91(x: Array[Nothing]): Unit = {} + def null$ARRAY_92(x: Array[Null]): Unit = {} + def nothing$ARRAY_93(x: Array[_ <: Nothing]): Unit = {} + def null$ARRAY_94(x: Array[_ <: Null]): Unit = {} } diff --git a/sbt-test/scala2-compat/erasure/dottyApp/Main.scala b/sbt-test/scala2-compat/erasure/dottyApp/Main.scala index a0f2df0c4e8c..ea359408692a 100644 --- a/sbt-test/scala2-compat/erasure/dottyApp/Main.scala +++ b/sbt-test/scala2-compat/erasure/dottyApp/Main.scala @@ -53,10 +53,10 @@ object Main { z.c_40(dummy) z.c_41(dummy) z.c_42(dummy) - z.b_43(dummy) + //z.b_43(dummy) z.c_44(dummy) z.c_45(dummy) - z.b_46(dummy) + //z.b_46(dummy) z.c_47(dummy) // z.a_48(dummy) // z.c_49(dummy) @@ -103,8 +103,8 @@ object Main { z.objectARRAY_90(dummy) z.objectARRAY_91(dummy) z.objectARRAY_92(dummy) - z.objectARRAY_93(dummy) - z.objectARRAY_94(dummy) + //z.objectARRAY_93(dummy) + //z.objectARRAY_94(dummy) val methods = classOf[scala2Lib.Z].getDeclaredMethods.toList ++ classOf[dottyApp.Z].getDeclaredMethods.toList methods.foreach { m => From 59ea93ebab2c6cd7ff93b30644e75fe365850b77 Mon Sep 17 00:00:00 2001 From: Hamza Remmal Date: Wed, 5 Feb 2025 15:53:15 +0100 Subject: [PATCH 069/505] fix: align Scala 2's erasure of Array[? <: Null] and Array[? <: Nothing] with Scala 2 [Cherry-picked f77b1f9ec59bb2c48f892d077dbfcf3d09d98698] --- .../dotty/tools/dotc/core/TypeErasure.scala | 18 +++++++++--------- .../scala2-compat/erasure/dottyApp/Main.scala | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 85fcaae350dd..87672e18744b 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -327,7 +327,7 @@ object TypeErasure { val sym = t.symbol // Only a few classes have both primitives and references as subclasses. if (sym eq defn.AnyClass) || (sym eq defn.AnyValClass) || (sym eq defn.MatchableClass) || (sym eq defn.SingletonClass) - || isScala2 && !(t.derivesFrom(defn.ObjectClass) || t.isNullType) then + || isScala2 && !(t.derivesFrom(defn.ObjectClass) || t.isNullType | t.isNothingType) then NoSymbol // We only need to check for primitives because derived value classes in arrays are always boxed. else if sym.isPrimitiveValueClass then @@ -779,14 +779,14 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst private def eraseArray(tp: Type)(using Context) = { val defn.ArrayOf(elemtp) = tp: @unchecked - if (isGenericArrayElement(elemtp, isScala2 = sourceLanguage.isScala2)) defn.ObjectType - else - try - if sourceLanguage.isScala2 && (elemtp.isNullType || elemtp.isNothingType) then - JavaArrayType(defn.ObjectType) - else erasureFn(sourceLanguage, semiEraseVCs = false, isConstructor, isSymbol, inSigName)(elemtp) match - case _: WildcardType => WildcardType - case elem => JavaArrayType(elem) + if isGenericArrayElement(elemtp, isScala2 = sourceLanguage.isScala2) then + defn.ObjectType + else if sourceLanguage.isScala2 && (elemtp.hiBound.isNullType || elemtp.hiBound.isNothingType) then + JavaArrayType(defn.ObjectType) + else + try erasureFn(sourceLanguage, semiEraseVCs = false, isConstructor, isSymbol, inSigName)(elemtp) match + case _: WildcardType => WildcardType + case elem => JavaArrayType(elem) catch case ex: Throwable => handleRecursive("erase array type", tp.show, ex) } diff --git a/sbt-test/scala2-compat/erasure/dottyApp/Main.scala b/sbt-test/scala2-compat/erasure/dottyApp/Main.scala index ea359408692a..48b9575302a0 100644 --- a/sbt-test/scala2-compat/erasure/dottyApp/Main.scala +++ b/sbt-test/scala2-compat/erasure/dottyApp/Main.scala @@ -103,8 +103,8 @@ object Main { z.objectARRAY_90(dummy) z.objectARRAY_91(dummy) z.objectARRAY_92(dummy) - //z.objectARRAY_93(dummy) - //z.objectARRAY_94(dummy) + z.objectARRAY_93(dummy) + z.objectARRAY_94(dummy) val methods = classOf[scala2Lib.Z].getDeclaredMethods.toList ++ classOf[dottyApp.Z].getDeclaredMethods.toList methods.foreach { m => From bae72d89a4ee8566d08987aebbb9cb4f2ef2b903 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Mon, 21 Apr 2025 14:25:50 +0200 Subject: [PATCH 070/505] bugfix: Fix compilation after backport --- .../src/main/dotty/tools/pc/PcInlayHintsProvider.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala index cf4929dfc91d..5d8739fb3343 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala @@ -57,7 +57,7 @@ class PcInlayHintsProvider( .headOption .getOrElse(unit.tpdTree) .enclosedChildren(pos.span) - .flatMap(tpdTree => deepFolder(InlayHints.empty(params.uri()), tpdTree).result()) + .flatMap(tpdTree => deepFolder(InlayHints.empty(params.uri().nn), tpdTree).result()) private def adjustPos(pos: SourcePosition): SourcePosition = pos.adjust(text)._1 From 7ce264bf1378255c41a8bc4ea05beeb4a4580353 Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Thu, 6 Feb 2025 11:00:55 +0100 Subject: [PATCH 071/505] Check if a prefix is valid before selecting from a type (#22368) closes #22357 --------- Co-authored-by: Katarzyna Marek <26606662+kasiaMarek@users.noreply.github.com> --- compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala | 2 +- tests/neg/i22357.check | 4 ++++ tests/neg/i22357.scala | 2 ++ tests/neg/i22357a.check | 4 ++++ tests/neg/i22357a.scala | 2 ++ 5 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 tests/neg/i22357.check create mode 100644 tests/neg/i22357.scala create mode 100644 tests/neg/i22357a.check create mode 100644 tests/neg/i22357a.scala diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index ba9975923df0..f7edc82270bf 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -157,7 +157,7 @@ trait TypeAssigner { else qualType.findMember(name, pre) - if reallyExists(mbr) then qualType.select(name, mbr) + if reallyExists(mbr) && NamedType.validPrefix(qualType) then qualType.select(name, mbr) else if qualType.isErroneous || name.toTermName == nme.ERROR then UnspecifiedErrorType else NoType end selectionType diff --git a/tests/neg/i22357.check b/tests/neg/i22357.check new file mode 100644 index 000000000000..213782a7fc6c --- /dev/null +++ b/tests/neg/i22357.check @@ -0,0 +1,4 @@ +-- Error: tests/neg/i22357.scala:1:0 ----------------------------------------------------------------------------------- +1 |@([A] =>> Int) // error + |^^^^^^^^^^^^^^ + |[A] =>> Int does not have a constructor diff --git a/tests/neg/i22357.scala b/tests/neg/i22357.scala new file mode 100644 index 000000000000..d572c150fb81 --- /dev/null +++ b/tests/neg/i22357.scala @@ -0,0 +1,2 @@ +@([A] =>> Int) // error +def i = 1 diff --git a/tests/neg/i22357a.check b/tests/neg/i22357a.check new file mode 100644 index 000000000000..9b2bcd2510d4 --- /dev/null +++ b/tests/neg/i22357a.check @@ -0,0 +1,4 @@ +-- Error: tests/neg/i22357a.scala:2:6 ---------------------------------------------------------------------------------- +2 | new ([A] =>> Int)(2) // error + | ^^^^^^^^^^^^^ + | [A] =>> Int does not have a constructor diff --git a/tests/neg/i22357a.scala b/tests/neg/i22357a.scala new file mode 100644 index 000000000000..b6c9c04fb268 --- /dev/null +++ b/tests/neg/i22357a.scala @@ -0,0 +1,2 @@ +def main = + new ([A] =>> Int)(2) // error From 68ccd8aec54c539b8e8533af7ce264776260d42a Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Tue, 22 Apr 2025 10:11:42 +0200 Subject: [PATCH 072/505] Check if a prefix is valid before selecting from a type (#22368) closes #22357 --------- Co-authored-by: Katarzyna Marek <26606662+kasiaMarek@users.noreply.github.com> [Cherry-picked a56c622af94f4131d5477b33f9a15745f2bd883e][modified] From db194a8f3fc3ba653f8b21fb8edcc8ffa9490617 Mon Sep 17 00:00:00 2001 From: kasiaMarek Date: Thu, 30 Jan 2025 14:05:27 +0100 Subject: [PATCH 073/505] improvement: use heuristic to figure out `nameSpan` if `pointDelta` to big [Cherry-picked 9ef55796d7f72085657b014bbef25aa1bb77478d] --- compiler/src/dotty/tools/dotc/ast/Trees.scala | 7 +- .../src/dotty/tools/dotc/util/Spans.scala | 3 + .../highlight/DocumentHighlightSuite.scala | 101 ++++++++++++++++++ 3 files changed, 109 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index dc8c2add27be..9cfacf3b42fa 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -460,8 +460,11 @@ object Trees { else if qualifier.span.exists && qualifier.span.start > span.point then // right associative val realName = name.stripModuleClassSuffix.lastPart Span(span.start, span.start + realName.length, point) - else - Span(point, span.end, point) + else if span.pointMayBeIncorrect then + val realName = name.stripModuleClassSuffix.lastPart + val probablyPoint = span.end - realName.length + Span(probablyPoint, span.end, probablyPoint) + else Span(point, span.end, point) else span } diff --git a/compiler/src/dotty/tools/dotc/util/Spans.scala b/compiler/src/dotty/tools/dotc/util/Spans.scala index e1487408f36b..7d4bbe0e8180 100644 --- a/compiler/src/dotty/tools/dotc/util/Spans.scala +++ b/compiler/src/dotty/tools/dotc/util/Spans.scala @@ -59,6 +59,9 @@ object Spans { if (poff == SyntheticPointDelta) start else start + poff } + def pointMayBeIncorrect = + pointDelta == 0 && end - start >= SyntheticPointDelta + /** The difference between point and start in this span */ def pointDelta: Int = (coords >>> (StartEndBits * 2)).toInt diff --git a/presentation-compiler/test/dotty/tools/pc/tests/highlight/DocumentHighlightSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/highlight/DocumentHighlightSuite.scala index 5d9893f6a1c1..0586a0648ac3 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/highlight/DocumentHighlightSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/highlight/DocumentHighlightSuite.scala @@ -1462,5 +1462,106 @@ class DocumentHighlightSuite extends BaseDocumentHighlightSuite: |""".stripMargin ) + @Test def i3053 = + check( + """import Aaaa.* + | + |def classDef2(cdef: List[Int]): Int = { + | def aaa(ddef: Thicket2): List[Int] = ddef match { + | case Thicket2(_) => ??? + | } + | + | /** Does `tree' look like a reference to AnyVal? Temporary test before we have + | * inline classes + | */ + | // The original type and value parameters in the constructor already have the flags + | // needed to be type members (i.e. param, and possibly also private and local unless + | // prefixed by type or val). `tparams` and `vparamss` are the type parameters that + | // go in `constr`, the constructor after desugaring. + | + | /** Does `tree' look like a reference to AnyVal? Temporary test before we have + | * inline classes + | */ + | // The original type and value parameters in the constructor already have the flags + | // needed to be type members (i.e. param, and possibly also private and local unless + | // prefixed by type or val). `tparams` and `vparamss` are the type parameters that + | // go in `constr`, the constructor after desugaring. + | + | /** Does `tree' look like a reference to AnyVal? Temporary test before we have + | * inline classes + | */ + | // Annotations on class _type_ parameters are set on the derived parameters + | // but not on the constructor parameters. The reverse is true for + | // annotations on class _value_ parameters. + | // The original type and value parameters in the constructor already have the flags + | // needed to be type members (i.e. param, and possibly also private and local unless + | // prefixed by type or val). `tparams` and `vparamss` are the type parameters that + | // go in `constr`, the constructor after desugaring. + | // The original type and value parameters in the constructor already have the flags + | // needed to be type members (i.e. param, and possibly also private and local unless + | // prefixed by type or val). `tparams` and `vparamss` are the type parameters that + | // go in `constr`, the constructor after desugaring. + | + | /** Does `tree' look like a reference to AnyVal? Temporary test before we have + | * inline classes + | */ + | // The original type and value parameters in the constructor already have the flags + | // needed to be type members (i.e. param, and possibly also private and local unless + | // prefixed by type or val). `tparams` and `vparamss` are the type parameters that + | // go in `constr`, the constructor after desugaring. + | + | /** Does `tree' look like a reference to AnyVal? Temporary test before we have + | * inline classes + | */ + | + | // Annotations on class _type_ parameters are set on the derived parameters + | // but not on the constructor parameters. The reverse is true for + | // annotations on class _value_ parameters. + | // The original type and value parameters in the constructor already have the flags + | // needed to be type members (i.e. param, and possibly also private and local unless + | // prefixed by type or val). `tparams` and `vparamss` are the type parameters that + | // go in `constr`, the constructor after desugaring. + | // The original type and value parameters in the constructor already have the flags + | // needed to be type members (i.e. param, and possibly also private and local unless + | // prefixed by type or val). `tparams` and `vparamss` are the type parameters that + | // go in `constr`, the constructor after desugaring. + | + | /** Does `tree' look like a reference to AnyVal? Temporary test before we have + | * inline classes + | */ + | // The original type and value parameters in the constructor already have the flags + | // needed to be type members (i.e. param, and possibly also private and local unless + | // prefixed by type or val). `tparams` and `vparamss` are the type parameters that + | // go in `constr`, the constructor after desugaring. + | + | /** Does `tree' look like a reference to AnyVal? Temporary test before we have + | * inline classes + | */ + | // Annotations on class _type_ parameters are set on the derived parameters + | // but not on the constructor parameters. The reverse is true for + | // annotations on class _value_ parameters. + | // The original type and value parameters in the constructor already have the flags + | // needed to be type members (i.e. param, and possibly also private and local unless + | // prefixed by type or val). `tparams` and `vparamss` are the type parameters that + | // go in `constr`, the constructor after desugaring. + | // The original type and value parameters in the constructor already have the flags + | // needed to be type members (i.e. param, and possibly also private and local unless + | // prefixed by type or val). `tparams` and `vparamss` are the type parameters that + | // go in `constr`, the constructor after desugaring. + | 1 + |}.<>("aaa") + | + |case class Thicket2(trees: List[Int]) {} + | + |object Aaaa { + | extension [T](x: T) + | def <>[U](aaa: String): T = { + | x + | } + |} + | + |""".stripMargin + ) + end DocumentHighlightSuite From 07bea7e2bf77daeef0d6bbb0ff27c36eb6afc27a Mon Sep 17 00:00:00 2001 From: kasiaMarek Date: Thu, 6 Feb 2025 15:20:08 +0100 Subject: [PATCH 074/505] test: shorten test [Cherry-picked a6252544116df0a6f80f8937d9f52532760b8001] --- .../highlight/DocumentHighlightSuite.scala | 81 +------------------ 1 file changed, 2 insertions(+), 79 deletions(-) diff --git a/presentation-compiler/test/dotty/tools/pc/tests/highlight/DocumentHighlightSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/highlight/DocumentHighlightSuite.scala index 0586a0648ac3..4809bc5cd5b8 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/highlight/DocumentHighlightSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/highlight/DocumentHighlightSuite.scala @@ -1464,90 +1464,13 @@ class DocumentHighlightSuite extends BaseDocumentHighlightSuite: @Test def i3053 = check( - """import Aaaa.* + s"""import Aaaa.* | |def classDef2(cdef: List[Int]): Int = { | def aaa(ddef: Thicket2): List[Int] = ddef match { | case Thicket2(_) => ??? | } - | - | /** Does `tree' look like a reference to AnyVal? Temporary test before we have - | * inline classes - | */ - | // The original type and value parameters in the constructor already have the flags - | // needed to be type members (i.e. param, and possibly also private and local unless - | // prefixed by type or val). `tparams` and `vparamss` are the type parameters that - | // go in `constr`, the constructor after desugaring. - | - | /** Does `tree' look like a reference to AnyVal? Temporary test before we have - | * inline classes - | */ - | // The original type and value parameters in the constructor already have the flags - | // needed to be type members (i.e. param, and possibly also private and local unless - | // prefixed by type or val). `tparams` and `vparamss` are the type parameters that - | // go in `constr`, the constructor after desugaring. - | - | /** Does `tree' look like a reference to AnyVal? Temporary test before we have - | * inline classes - | */ - | // Annotations on class _type_ parameters are set on the derived parameters - | // but not on the constructor parameters. The reverse is true for - | // annotations on class _value_ parameters. - | // The original type and value parameters in the constructor already have the flags - | // needed to be type members (i.e. param, and possibly also private and local unless - | // prefixed by type or val). `tparams` and `vparamss` are the type parameters that - | // go in `constr`, the constructor after desugaring. - | // The original type and value parameters in the constructor already have the flags - | // needed to be type members (i.e. param, and possibly also private and local unless - | // prefixed by type or val). `tparams` and `vparamss` are the type parameters that - | // go in `constr`, the constructor after desugaring. - | - | /** Does `tree' look like a reference to AnyVal? Temporary test before we have - | * inline classes - | */ - | // The original type and value parameters in the constructor already have the flags - | // needed to be type members (i.e. param, and possibly also private and local unless - | // prefixed by type or val). `tparams` and `vparamss` are the type parameters that - | // go in `constr`, the constructor after desugaring. - | - | /** Does `tree' look like a reference to AnyVal? Temporary test before we have - | * inline classes - | */ - | - | // Annotations on class _type_ parameters are set on the derived parameters - | // but not on the constructor parameters. The reverse is true for - | // annotations on class _value_ parameters. - | // The original type and value parameters in the constructor already have the flags - | // needed to be type members (i.e. param, and possibly also private and local unless - | // prefixed by type or val). `tparams` and `vparamss` are the type parameters that - | // go in `constr`, the constructor after desugaring. - | // The original type and value parameters in the constructor already have the flags - | // needed to be type members (i.e. param, and possibly also private and local unless - | // prefixed by type or val). `tparams` and `vparamss` are the type parameters that - | // go in `constr`, the constructor after desugaring. - | - | /** Does `tree' look like a reference to AnyVal? Temporary test before we have - | * inline classes - | */ - | // The original type and value parameters in the constructor already have the flags - | // needed to be type members (i.e. param, and possibly also private and local unless - | // prefixed by type or val). `tparams` and `vparamss` are the type parameters that - | // go in `constr`, the constructor after desugaring. - | - | /** Does `tree' look like a reference to AnyVal? Temporary test before we have - | * inline classes - | */ - | // Annotations on class _type_ parameters are set on the derived parameters - | // but not on the constructor parameters. The reverse is true for - | // annotations on class _value_ parameters. - | // The original type and value parameters in the constructor already have the flags - | // needed to be type members (i.e. param, and possibly also private and local unless - | // prefixed by type or val). `tparams` and `vparamss` are the type parameters that - | // go in `constr`, the constructor after desugaring. - | // The original type and value parameters in the constructor already have the flags - | // needed to be type members (i.e. param, and possibly also private and local unless - | // prefixed by type or val). `tparams` and `vparamss` are the type parameters that - | // go in `constr`, the constructor after desugaring. + |${("//" + "x" * 64 + "\n") * 64} | 1 |}.<>("aaa") | From 2372eda97e29cccb6a70bba8c6b97f21af0c5185 Mon Sep 17 00:00:00 2001 From: Hamza Remmal Date: Fri, 7 Feb 2025 15:18:49 +0100 Subject: [PATCH 075/505] fix: allow private members when computing the denotation of a NamedType [Cherry-picked 6d003056e083386218889f8a132b6ee72ce32b61] --- compiler/src/dotty/tools/dotc/core/Types.scala | 2 +- tests/pos/i22548.scala | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 tests/pos/i22548.scala diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 1113f7413e6e..6c871f829941 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2412,7 +2412,7 @@ object Types extends TypeUtils { else lastd match { case lastd: SymDenotation => if stillValid(lastd) && checkedPeriod.code != NowhereCode then finish(lastd.current) - else finish(memberDenot(lastd.initial.name, allowPrivate = false)) + else finish(memberDenot(lastd.initial.name, allowPrivate = lastd.is(Private))) case _ => fromDesignator } diff --git a/tests/pos/i22548.scala b/tests/pos/i22548.scala new file mode 100644 index 000000000000..beb878d92670 --- /dev/null +++ b/tests/pos/i22548.scala @@ -0,0 +1,2 @@ +trait Bar[T] +class Foo[T <: Bar[T]] (private val buffer: Any) extends AnyVal From a00e32132ab4ee327a6b544749f31eab9dd92882 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Wed, 29 Jan 2025 15:32:15 -0800 Subject: [PATCH 076/505] More OG tests --- tests/pos/i22193.scala | 141 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 tests/pos/i22193.scala diff --git a/tests/pos/i22193.scala b/tests/pos/i22193.scala new file mode 100644 index 000000000000..2ba7f920fbd7 --- /dev/null +++ b/tests/pos/i22193.scala @@ -0,0 +1,141 @@ + +def fn2(arg: String, arg2: String)(f: String => Unit): Unit = f(arg) + +def fn3(arg: String, arg2: String)(f: => Unit): Unit = f + +def test() = + + fn2(arg = "blue sleeps faster than tuesday", arg2 = "the quick brown fox jumped over the lazy dog"): env => + val x = env + println(x) + + // doesn't compile + fn2( + arg = "blue sleeps faster than tuesday", + arg2 = "the quick brown fox jumped over the lazy dog"): env => + val x = env + println(x) + + fn2( + arg = "blue sleeps faster than tuesday", + arg2 = "the quick brown fox jumped over the lazy dog"): env => + val x = env + println(x) + + fn2( + arg = "blue sleeps faster than tuesday", + arg2 = "the quick brown fox jumped over the lazy dog"): env => + val x = env + println(x) + + // does compile + fn2( + arg = "blue sleeps faster than tuesday", + arg2 = "the quick brown fox jumped over the lazy dog"): + env => + val x = env + println(x) + + // does compile + fn2( + arg = "blue sleeps faster than tuesday", + arg2 = "the quick brown fox jumped over the lazy dog" + ): env => + val x = env + println(x) + + fn2( + arg = "blue sleeps faster than tuesday", + arg2 = "the quick brown fox jumped over the lazy dog" + ): env => + val x = env + println(x) + + fn3( + arg = "blue sleeps faster than tuesday", + arg2 = "the quick brown fox jumped over the lazy dog"): + val x = "Hello" + println(x) + + fn3( + arg = "blue sleeps faster than tuesday", + arg2 = "the quick brown fox jumped over the lazy dog"): + val x = "Hello" + println(x) + + fn3( // arg at 3, body at 3 + arg = "blue sleeps faster than tuesday", + arg2 = "the quick brown fox jumped over the lazy dog"): + val x = "Hello" + println(x) + + fn3( // arg at 3, body at 1: not sure if sig indent of 1 is allowed, saw some comments from odersky + arg = "blue sleeps faster than tuesday", + arg2 = "the quick brown fox jumped over the lazy dog"): + val x = "Hello" + println(x) + + fn3( // arg at 3, body at 2: even if sig indent of 1 is not allowed, body is at fn3+2, not arg2-1 + arg = "blue sleeps faster than tuesday", + arg2 = "the quick brown fox jumped over the lazy dog"): + val x = "Hello" + println(x) + + fn3( // arg at 3, body at 4 + arg = "blue sleeps faster than tuesday", + arg2 = "the quick brown fox jumped over the lazy dog"): + val x = "Hello" + println(x) + +// don't turn innocent empty cases into functions +def regress(x: Int) = + x match + case 42 => + case _ => + +// previously lookahead calculated indent width at the colon +def k(xs: List[Int]) = + xs.foldLeft( + 0) + : (acc, x) => + acc + x + +def `test kit`(xs: List[Int]): Unit = + def addOne(i: Int): Int = i + 1 + def isPositive(i: Int): Boolean = i > 0 + // doesn't compile but would be nice + // first body is indented "twice", or, rather, first outdent establishes an intermediate indentation level + xs.map: x => + x + 1 + .filter: x => + x > 0 + xs.map: + addOne + .filter: + isPositive + + // does compile + xs + .map: x => + x + 1 + .filter: x => + x > 0 + + // does compile but doesn't look good, at least, to some people + xs.map: x => + x + 1 + .filter: x => + x > 0 + +def `tested kit`(xs: List[Int]): Unit = + { + def addOne(i: Int): Int = i.+(1) + def isPositive(i: Int): Boolean = i.>(0) + xs.map[Int]((x: Int) => x.+(1)).filter((x: Int) => x.>(0)) + xs.map[Int]((i: Int) => addOne(i)).filter((i: Int) => isPositive(i)) + xs.map[Int]((x: Int) => x.+(1)).filter((x: Int) => x.>(0)) + { + xs.map[Int]((x: Int) => x.+(1)).filter((x: Int) => x.>(0)) + () + } + } From e39adecab6bc657c170a8c4171d8e1b27a952841 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Tue, 22 Apr 2025 10:50:16 +0200 Subject: [PATCH 077/505] More OG tests [Cherry-picked f5ba8d6e6df4cd3674bdeb8da9f09dbd1d8dcb53][modified] From 814cf6469815189ad4c1cc9763433fda88a67587 Mon Sep 17 00:00:00 2001 From: Alec Theriault Date: Tue, 4 Feb 2025 07:18:23 -0500 Subject: [PATCH 078/505] Better LSP completions inside of backticks This improves the presentation compiler name completions inside of backticks. The existing gaps which motivate doing this are outlined in [this Metals feature request][0]. [0]: https://github.com/scalameta/metals-feature-requests/issues/418 [Cherry-picked 936f7ad0eff0f187c7f7dfba88f9fd71e6b2d721] --- .../tools/dotc/interactive/Completion.scala | 9 +-- .../tools/pc/completions/CompletionPos.scala | 33 +++++++++-- .../pc/completions/CompletionProvider.scala | 11 +++- .../completion/CompletionBacktickSuite.scala | 57 +++++++++++++++++++ 4 files changed, 98 insertions(+), 12 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/interactive/Completion.scala b/compiler/src/dotty/tools/dotc/interactive/Completion.scala index af27a4006140..61a1db44d8b0 100644 --- a/compiler/src/dotty/tools/dotc/interactive/Completion.scala +++ b/compiler/src/dotty/tools/dotc/interactive/Completion.scala @@ -145,11 +145,12 @@ object Completion: checkBacktickPrefix(ident.source.content(), ident.span.start, ident.span.end) case (tree: untpd.RefTree) :: _ if tree.name != nme.ERROR => - tree.name.toString.take(pos.span.point - tree.span.point) - - case _ => naiveCompletionPrefix(pos.source.content().mkString, pos.point) - + val nameStart = tree.span.point + val start = if pos.source.content().lift(nameStart).contains('`') then nameStart + 1 else nameStart + tree.name.toString.take(pos.span.point - start) + case _ => + naiveCompletionPrefix(pos.source.content().mkString, pos.point) end completionPrefix private object GenericImportSelector: diff --git a/presentation-compiler/src/main/dotty/tools/pc/completions/CompletionPos.scala b/presentation-compiler/src/main/dotty/tools/pc/completions/CompletionPos.scala index 6d89cb663b9c..40f1ccd2e797 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/completions/CompletionPos.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/completions/CompletionPos.scala @@ -23,7 +23,9 @@ case class CompletionPos( query: String, originalCursorPosition: SourcePosition, sourceUri: URI, - withCURSOR: Boolean + withCURSOR: Boolean, + hasLeadingBacktick: Boolean, + hasTrailingBacktick: Boolean ): def queryEnd: Int = originalCursorPosition.point def stripSuffixEditRange: l.Range = new l.Range(originalCursorPosition.offsetToPos(queryStart), originalCursorPosition.offsetToPos(identEnd)) @@ -38,16 +40,35 @@ object CompletionPos: adjustedPath: List[Tree], wasCursorApplied: Boolean )(using Context): CompletionPos = - val identEnd = adjustedPath match + def hasBacktickAt(offset: Int): Boolean = + sourcePos.source.content().lift(offset).contains('`') + + val (identEnd, hasTrailingBacktick) = adjustedPath match case (refTree: RefTree) :: _ if refTree.name.toString.contains(Cursor.value) => - refTree.span.end - Cursor.value.length - case (refTree: RefTree) :: _ => refTree.span.end - case _ => sourcePos.end + val refTreeEnd = refTree.span.end + val hasTrailingBacktick = hasBacktickAt(refTreeEnd - 1) + val identEnd = refTreeEnd - Cursor.value.length + (if hasTrailingBacktick then identEnd - 1 else identEnd, hasTrailingBacktick) + case (refTree: RefTree) :: _ => + val refTreeEnd = refTree.span.end + val hasTrailingBacktick = hasBacktickAt(refTreeEnd - 1) + (if hasTrailingBacktick then refTreeEnd - 1 else refTreeEnd, hasTrailingBacktick) + case _ => (sourcePos.end, false) val query = Completion.completionPrefix(adjustedPath, sourcePos) val start = sourcePos.end - query.length() + val hasLeadingBacktick = hasBacktickAt(start - 1) - CompletionPos(start, identEnd, query.nn, sourcePos, offsetParams.uri.nn, wasCursorApplied) + CompletionPos( + start, + identEnd, + query.nn, + sourcePos, + offsetParams.uri.nn, + wasCursorApplied, + hasLeadingBacktick, + hasTrailingBacktick + ) /** * Infer the indentation by counting the number of spaces in the given line. diff --git a/presentation-compiler/src/main/dotty/tools/pc/completions/CompletionProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/completions/CompletionProvider.scala index 28519debec63..8c8dd09c8c15 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/completions/CompletionProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/completions/CompletionProvider.scala @@ -248,10 +248,17 @@ class CompletionProvider( range: Option[LspRange] = None ): CompletionItem = val oldText = params.text().nn.substring(completionPos.queryStart, completionPos.identEnd) - val editRange = if newText.startsWith(oldText) then completionPos.stripSuffixEditRange + val trimmedNewText = { + var nt = newText + if (completionPos.hasLeadingBacktick) nt = nt.stripPrefix("`") + if (completionPos.hasTrailingBacktick) nt = nt.stripSuffix("`") + nt + } + + val editRange = if trimmedNewText.startsWith(oldText) then completionPos.stripSuffixEditRange else completionPos.toEditRange - val textEdit = new TextEdit(range.getOrElse(editRange), wrapInBracketsIfRequired(newText)) + val textEdit = new TextEdit(range.getOrElse(editRange), wrapInBracketsIfRequired(trimmedNewText)) val item = new CompletionItem(label) item.setSortText(f"${idx}%05d") diff --git a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionBacktickSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionBacktickSuite.scala index 5d13c60b2fd5..d41261d2d21e 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionBacktickSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionBacktickSuite.scala @@ -179,3 +179,60 @@ class CompletionBacktickSuite extends BaseCompletionSuite: |} |""".stripMargin ) + + @Test def `add-backticks-around-identifier` = + checkEdit( + """|object Main { + | def `Foo Bar` = 123 + | Foo@@ + |} + |""".stripMargin, + """|object Main { + | def `Foo Bar` = 123 + | `Foo Bar` + |} + |""".stripMargin + ) + + @Test def `complete-inside-backticks` = + checkEdit( + """|object Main { + | def `Foo Bar` = 123 + | `Foo@@` + |} + |""".stripMargin, + """|object Main { + | def `Foo Bar` = 123 + | `Foo Bar` + |} + |""".stripMargin + ) + + @Test def `complete-inside-backticks-after-space` = + checkEdit( + """|object Main { + | def `Foo Bar` = 123 + | `Foo B@@a` + |} + |""".stripMargin, + """|object Main { + | def `Foo Bar` = 123 + | `Foo Bar` + |} + |""".stripMargin + ) + + @Test def `complete-inside-empty-backticks` = + checkEdit( + """|object Main { + | def `Foo Bar` = 123 + | `@@` + |} + |""".stripMargin, + """|object Main { + | def `Foo Bar` = 123 + | `Foo Bar` + |} + |""".stripMargin, + filter = _ == "Foo Bar: Int" + ) From 31b57b30d83046b428b2016dd86bf862932e9fc1 Mon Sep 17 00:00:00 2001 From: kasiaMarek Date: Mon, 10 Feb 2025 15:01:52 +0100 Subject: [PATCH 079/505] fix: don't add `()` to semanticdb symbol for java variables [Cherry-picked 38154ba9bb857a46b0ab3546dfa67be1881cc2d1] --- .../semanticdb/SemanticSymbolBuilder.scala | 2 +- .../expect/JavaStaticVar.expect.scala | 7 +++++ tests/semanticdb/expect/JavaStaticVar.scala | 7 +++++ .../javacp/com/javacp/JavaStaticVar.java | 5 ++++ tests/semanticdb/metac.expect | 27 +++++++++++++++++++ 5 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 tests/semanticdb/expect/JavaStaticVar.expect.scala create mode 100644 tests/semanticdb/expect/JavaStaticVar.scala create mode 100644 tests/semanticdb/javacp/com/javacp/JavaStaticVar.java diff --git a/compiler/src/dotty/tools/dotc/semanticdb/SemanticSymbolBuilder.scala b/compiler/src/dotty/tools/dotc/semanticdb/SemanticSymbolBuilder.scala index 81f5d37f443f..077ee0e40b86 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/SemanticSymbolBuilder.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/SemanticSymbolBuilder.scala @@ -111,7 +111,7 @@ class SemanticSymbolBuilder: addName(b, sym.name) if sym.is(Package) then b.append('/') else if sym.isType || sym.isAllOf(JavaModule) then b.append('#') - else if sym.isOneOf(Method | Mutable) + else if sym.is(Method) || (sym.is(Mutable) && !sym.is(JavaDefined)) && (!sym.is(StableRealizable) || sym.isConstructor) then b.append('('); addOverloadIdx(sym); b.append(").") else b.append('.') diff --git a/tests/semanticdb/expect/JavaStaticVar.expect.scala b/tests/semanticdb/expect/JavaStaticVar.expect.scala new file mode 100644 index 000000000000..171596bc9519 --- /dev/null +++ b/tests/semanticdb/expect/JavaStaticVar.expect.scala @@ -0,0 +1,7 @@ +package example + +import com.javacp.JavaStaticVar/*->com::javacp::JavaStaticVar#*/ + +class ScalaFoo/*<-example::ScalaFoo#*/ { + val javaStaticVarFoo/*<-example::ScalaFoo#javaStaticVarFoo.*/ = JavaStaticVar/*->com::javacp::JavaStaticVar#*/.foo/*->com::javacp::JavaStaticVar#foo.*/ +} diff --git a/tests/semanticdb/expect/JavaStaticVar.scala b/tests/semanticdb/expect/JavaStaticVar.scala new file mode 100644 index 000000000000..7a7efeaa670a --- /dev/null +++ b/tests/semanticdb/expect/JavaStaticVar.scala @@ -0,0 +1,7 @@ +package example + +import com.javacp.JavaStaticVar + +class ScalaFoo { + val javaStaticVarFoo = JavaStaticVar.foo +} diff --git a/tests/semanticdb/javacp/com/javacp/JavaStaticVar.java b/tests/semanticdb/javacp/com/javacp/JavaStaticVar.java new file mode 100644 index 000000000000..1124c8768421 --- /dev/null +++ b/tests/semanticdb/javacp/com/javacp/JavaStaticVar.java @@ -0,0 +1,5 @@ +package com.javacp; + +public class JavaStaticVar { + public static int foo = 0; +} diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index a89da0fb8aec..4e3dee9d79a6 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -2249,6 +2249,33 @@ Synthetics: [8:2..8:10):(x1, x1) => *(Tuple2(Int, Int)) [8:10..8:10): => *(Int, Int) +expect/JavaStaticVar.scala +-------------------------- + +Summary: +Schema => SemanticDB v4 +Uri => JavaStaticVar.scala +Text => empty +Language => Scala +Symbols => 3 entries +Occurrences => 9 entries + +Symbols: +example/ScalaFoo# => class ScalaFoo extends Object { self: ScalaFoo => +2 decls } +example/ScalaFoo#``(). => primary ctor (): ScalaFoo +example/ScalaFoo#javaStaticVarFoo. => val method javaStaticVarFoo Int + +Occurrences: +[0:8..0:15): example <- example/ +[2:7..2:10): com -> com/ +[2:11..2:17): javacp -> com/javacp/ +[2:18..2:31): JavaStaticVar -> com/javacp/JavaStaticVar# +[4:6..4:14): ScalaFoo <- example/ScalaFoo# +[5:2..5:2): <- example/ScalaFoo#``(). +[5:6..5:22): javaStaticVarFoo <- example/ScalaFoo#javaStaticVarFoo. +[5:25..5:38): JavaStaticVar -> com/javacp/JavaStaticVar# +[5:39..5:42): foo -> com/javacp/JavaStaticVar#foo. + expect/Local.scala ------------------ From 912fd2bcb339dee966a254036c7b7bad0aaaa723 Mon Sep 17 00:00:00 2001 From: aherlihy Date: Mon, 10 Feb 2025 13:46:52 +0100 Subject: [PATCH 080/505] Add warning for :kind command [Cherry-picked e399364ca0c3888c867f9014caeacbb6b74b7c70] --- compiler/src/dotty/tools/repl/ParseResult.scala | 8 ++++++++ compiler/src/dotty/tools/repl/ReplDriver.scala | 4 ++++ compiler/test-resources/repl/i21655 | 2 ++ compiler/test/dotty/tools/repl/TabcompleteTests.scala | 1 + 4 files changed, 15 insertions(+) create mode 100644 compiler/test-resources/repl/i21655 diff --git a/compiler/src/dotty/tools/repl/ParseResult.scala b/compiler/src/dotty/tools/repl/ParseResult.scala index 6c9f95d4dca2..2674a385a10c 100644 --- a/compiler/src/dotty/tools/repl/ParseResult.scala +++ b/compiler/src/dotty/tools/repl/ParseResult.scala @@ -52,6 +52,13 @@ object Load { val command: String = ":load" } +/** `:kind ` display the kind of a type. see also :help kind + */ +case class KindOf(expr: String) extends Command +object KindOf { + val command: String = ":kind" +} + /** To find out the type of an expression you may simply do: * * ``` @@ -138,6 +145,7 @@ object ParseResult { Help.command -> (_ => Help), Reset.command -> (arg => Reset(arg)), Imports.command -> (_ => Imports), + KindOf.command -> (arg => KindOf(arg)), Load.command -> (arg => Load(arg)), TypeOf.command -> (arg => TypeOf(arg)), DocOf.command -> (arg => DocOf(arg)), diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index d7ba2d3ce193..bd97336fc792 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -511,6 +511,10 @@ class ReplDriver(settings: Array[String], state } + case KindOf(expr) => + out.println(s"""The :kind command is not currently supported.""") + state + case TypeOf(expr) => expr match { case "" => out.println(s":type ") diff --git a/compiler/test-resources/repl/i21655 b/compiler/test-resources/repl/i21655 new file mode 100644 index 000000000000..57b09bfad32d --- /dev/null +++ b/compiler/test-resources/repl/i21655 @@ -0,0 +1,2 @@ +scala>:kind +The :kind command is not currently supported. \ No newline at end of file diff --git a/compiler/test/dotty/tools/repl/TabcompleteTests.scala b/compiler/test/dotty/tools/repl/TabcompleteTests.scala index 963d680b69bc..8c817dc2b96f 100644 --- a/compiler/test/dotty/tools/repl/TabcompleteTests.scala +++ b/compiler/test/dotty/tools/repl/TabcompleteTests.scala @@ -216,6 +216,7 @@ class TabcompleteTests extends ReplTest { ":exit", ":help", ":imports", + ":kind", ":load", ":quit", ":reset", From 2333135cba6dd3dc1c1890dfa352b81b0af2d3a7 Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Tue, 11 Feb 2025 18:09:30 +0100 Subject: [PATCH 081/505] fix: Only fallback to the definition of a synthetic valdef if it is zero extent (#22551) closes scalameta/metals#7038 closes scalameta/metals#7191 fixes the reproduction issue from #22217 Co-authored-by: Katarzyna Marek <26606662+kasiaMarek@users.noreply.github.com> [Cherry-picked 37206cc4a7e8a6ab60f0b54b4716bc65b9333940] --- .../tools/pc/completions/CompletionProvider.scala | 4 ++-- .../tools/pc/tests/completion/CompletionSuite.scala | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/completions/CompletionProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/completions/CompletionProvider.scala index 8c8dd09c8c15..2a63d6a92a81 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/completions/CompletionProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/completions/CompletionProvider.scala @@ -99,9 +99,9 @@ class CompletionProvider( * 4| $1$.sliding@@[Int](size, step) * */ - if qual.symbol.is(Flags.Synthetic) && qual.symbol.name.isInstanceOf[DerivedName] => + if qual.symbol.is(Flags.Synthetic) && qual.span.isZeroExtent && qual.symbol.name.isInstanceOf[DerivedName] => qual.symbol.defTree match - case valdef: ValDef => Select(valdef.rhs, name) :: tail + case valdef: ValDef if !valdef.rhs.isEmpty => Select(valdef.rhs, name) :: tail case _ => tpdPath0 case _ => tpdPath0 diff --git a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala index a3217f64d856..27aa3f505b80 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala @@ -2134,3 +2134,14 @@ class CompletionSuite extends BaseCompletionSuite: """|build: Unit |""".stripMargin, ) + + @Test def i7191 = + check( + """|val x = Some(3).map(_.@@) + |""".stripMargin, + """|!=(x: Byte): Boolean + |!=(x: Char): Boolean + |!=(x: Double): Boolean + |""".stripMargin, + topLines = Some(3) + ) From 2f045b1c350e4324cc9111657bdc86603697f083 Mon Sep 17 00:00:00 2001 From: Matt Bovel Date: Tue, 11 Feb 2025 15:32:55 +0000 Subject: [PATCH 082/505] Fix copy of annotation on @main methods [Cherry-picked 15c4e51b9028ca2a2938864428b2b69793934b14] --- .../src/dotty/tools/dotc/ast/MainProxies.scala | 16 ++++++++-------- tests/pos/annot-main-22364.scala | 5 +++++ tests/pos/annot-main-22364b.scala | 6 ++++++ tests/pos/annot-main-22364c.scala | 10 ++++++++++ 4 files changed, 29 insertions(+), 8 deletions(-) create mode 100644 tests/pos/annot-main-22364.scala create mode 100644 tests/pos/annot-main-22364b.scala create mode 100644 tests/pos/annot-main-22364c.scala diff --git a/compiler/src/dotty/tools/dotc/ast/MainProxies.scala b/compiler/src/dotty/tools/dotc/ast/MainProxies.scala index 8ee75cbf364b..d04dd82fb424 100644 --- a/compiler/src/dotty/tools/dotc/ast/MainProxies.scala +++ b/compiler/src/dotty/tools/dotc/ast/MainProxies.scala @@ -103,17 +103,17 @@ object MainProxies { val body = Try(call, handler :: Nil, EmptyTree) val mainArg = ValDef(nme.args, TypeTree(defn.ArrayType.appliedTo(defn.StringType)), EmptyTree) .withFlags(Param) - /** Replace typed `Ident`s that have been typed with a TypeSplice with the reference to the symbol. - * The annotations will be retype-checked in another scope that may not have the same imports. + + /** This context is used to create the `TypeSplices` wrapping annotations + * below. These should have `mainFun` as their owner (and not the + * enclosing package class that we would get otherwise) so that + * subsequent owner changes (for example in `Typer.typedTypedSplice`) are + * correct. See #22364 and associated tests. */ - def insertTypeSplices = new TreeMap { - override def transform(tree: Tree)(using Context): Tree = tree match - case tree: tpd.Ident @unchecked => TypedSplice(tree) - case tree => super.transform(tree) - } + val annotsCtx = ctx.fresh.setOwner(mainFun) val annots = mainFun.annotations .filterNot(_.matches(defn.MainAnnot)) - .map(annot => insertTypeSplices.transform(annot.tree)) + .map(annot => TypedSplice(annot.tree)(using annotsCtx)) val mainMeth = DefDef(nme.main, (mainArg :: Nil) :: Nil, TypeTree(defn.UnitType), body) .withFlags(JavaStatic | Synthetic) .withAnnotations(annots) diff --git a/tests/pos/annot-main-22364.scala b/tests/pos/annot-main-22364.scala new file mode 100644 index 000000000000..205589b525bc --- /dev/null +++ b/tests/pos/annot-main-22364.scala @@ -0,0 +1,5 @@ +def id[T](x: T): T = x + +class ann(x: Int) extends annotation.Annotation + +@ann(id(22)) @main def blop = () diff --git a/tests/pos/annot-main-22364b.scala b/tests/pos/annot-main-22364b.scala new file mode 100644 index 000000000000..c4e3067d7325 --- /dev/null +++ b/tests/pos/annot-main-22364b.scala @@ -0,0 +1,6 @@ +import util.chaining.* + +class ann(x: Int = 1, y: Int) extends annotation.Annotation + +@ann(y = 22.tap(println)) @main def blop = () + diff --git a/tests/pos/annot-main-22364c.scala b/tests/pos/annot-main-22364c.scala new file mode 100644 index 000000000000..53a6abe1a56b --- /dev/null +++ b/tests/pos/annot-main-22364c.scala @@ -0,0 +1,10 @@ +package p + +object P1: + class ann(x: Int) extends annotation.Annotation + +object P2: + def id[T](x: T): T = x + +object P3: + @P1.ann(P2.id(22)) @main def blop = () From 6acb0eb9783187b33c746bccac5a359f2a9b8581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Bra=C4=8Devac?= Date: Mon, 3 Feb 2025 19:18:19 +0100 Subject: [PATCH 083/505] Prevent Cyclic Exports on Current Class A member that is visible through inheritance or mixin should not be eligible for `export`. We perform the `derivesFrom` check in `canForward` now on the self-type of the exporting class to detect such cycles through mixins. Co-authored-by: Jan-Pieter van den Heuvel Co-authored-by: Willem W Bakker Co-authored-by: odersky [Cherry-picked 5e8eb7456d588cf647183e3ef97ba82d0254a45f] --- .../src/dotty/tools/dotc/typer/Namer.scala | 17 +++++++- tests/neg/exports3.scala | 41 +++++++++++++++++++ tests/neg/i20245.check | 14 +++++++ tests/neg/i20245/Typer_2.scala | 2 +- 4 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 tests/neg/exports3.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 0471bb6a432a..cea045cecc35 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -1130,11 +1130,26 @@ class Namer { typer: Typer => def canForward(mbr: SingleDenotation, alias: TermName): CanForward = { import CanForward.* val sym = mbr.symbol + /** + * The export selects a member of the current class (issue #22147). + * Assumes that cls.classInfo.selfType.derivesFrom(sym.owner) is true. + */ + def isCurrentClassMember: Boolean = expr match + case id: (Ident | This) => // Access through self type or this + /* Given the usage context below, where cls's self type is a subtype of sym.owner, + it suffices to check if symbol is the same class. */ + cls == id.symbol + case _ => false if !sym.isAccessibleFrom(pathType) then No("is not accessible") else if sym.isConstructor || sym.is(ModuleClass) || sym.is(Bridge) || sym.is(ConstructorProxy) || sym.isAllOf(JavaModule) then Skip - else if cls.derivesFrom(sym.owner) && (sym.owner == cls || !sym.is(Deferred)) then + // if the cls is a subclass or mixes in the owner of the symbol + // and either + // * the symbols owner is the cls itself + // * the symbol is not a deferred symbol + // * the symbol is a member of the current class (#22147) + else if cls.classInfo.selfType.derivesFrom(sym.owner) && (sym.owner == cls || !sym.is(Deferred) || isCurrentClassMember) then No(i"is already a member of $cls") else if pathMethod.exists && mbr.isType then No("is a type, so it cannot be exported as extension method") diff --git a/tests/neg/exports3.scala b/tests/neg/exports3.scala new file mode 100644 index 000000000000..eaea93d9f7ce --- /dev/null +++ b/tests/neg/exports3.scala @@ -0,0 +1,41 @@ +trait P: + def foo: Int + +class A extends P: + export this.foo // error + +trait Q extends P: + def bar: Int + +trait R extends P: + def baz: Int + val a1: A + val a2: A + +abstract class B extends R: + self => + export this.baz // error + export self.bar // error + export this.a1.foo + export self.a2.foo // error + export a2.foo // error + +abstract class D extends P: + val p: P + export p.foo + +abstract class E: + self: P => + export self.foo // error + +abstract class F: + self: P => + export this.foo // error + +class G(p: P): + self: P => + export p.foo + +class H(p: P): + self: P => + export this.p.foo \ No newline at end of file diff --git a/tests/neg/i20245.check b/tests/neg/i20245.check index 565bde7678b7..49d08c646f99 100644 --- a/tests/neg/i20245.check +++ b/tests/neg/i20245.check @@ -15,3 +15,17 @@ | Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace. | | longer explanation available when compiling with `-explain` +-- [E046] Cyclic Error: tests/neg/i20245/Typer_2.scala:10:7 ------------------------------------------------------------ +10 |import effekt.source.{ resolve } // error + | ^ + | Cyclic reference involving class Context + | + | The error occurred while trying to compute the base classes of class Context + | which required to compute the base classes of trait TyperOps + | which required to compute the signature of trait TyperOps + | which required to elaborate the export clause export unification.requireSubtype + | which required to compute the base classes of class Context + | + | Run with both -explain-cyclic and -Ydebug-cyclic to see full stack trace. + | + | longer explanation available when compiling with `-explain` diff --git a/tests/neg/i20245/Typer_2.scala b/tests/neg/i20245/Typer_2.scala index ed7f05de80d0..bf4718de759c 100644 --- a/tests/neg/i20245/Typer_2.scala +++ b/tests/neg/i20245/Typer_2.scala @@ -7,7 +7,7 @@ import effekt.util.messages.ErrorReporter import effekt.context.{ Context } // This import is also NECESSARY for the cyclic error -import effekt.source.{ resolve } +import effekt.source.{ resolve } // error trait TyperOps extends ErrorReporter { self: Context => From f52186d9c75185a0ad9452b024521d5cd5ce9038 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Tue, 22 Apr 2025 11:04:20 +0200 Subject: [PATCH 084/505] chore: Add changes from missing commits --- .../dotty/tools/dotc/parsing/Parsers.scala | 4 ++- .../dotty/tools/dotc/parsing/Scanners.scala | 24 +++++++++++--- tests/neg/i22193.scala | 32 +++++++++++++++++++ 3 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 tests/neg/i22193.scala diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 4bd7769187d5..4354be9662be 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -33,6 +33,7 @@ import config.Feature import config.Feature.{sourceVersion, migrateTo3, globalOnlyImports} import config.SourceVersion.* import config.SourceVersion +import dotty.tools.dotc.util.chaining.* object Parsers { @@ -1020,10 +1021,11 @@ object Parsers { */ def followingIsLambdaAfterColon(): Boolean = val lookahead = in.LookaheadScanner(allowIndent = true) + .tap(_.currentRegion.knownWidth = in.currentRegion.indentWidth) def isArrowIndent() = lookahead.isArrow && { - lookahead.nextToken() + lookahead.observeArrowIndented() lookahead.token == INDENT || lookahead.token == EOF } lookahead.nextToken() diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index 57a7ff1c4a9b..96e9cd600363 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -636,7 +636,6 @@ object Scanners { insert(OUTDENT, offset) else if r.isInstanceOf[InBraces] && !closingRegionTokens.contains(token) then report.warning("Line is indented too far to the left, or a `}` is missing", sourcePos()) - else if lastWidth < nextWidth || lastWidth == nextWidth && (lastToken == MATCH || lastToken == CATCH) && token == CASE then if canStartIndentTokens.contains(lastToken) then @@ -656,7 +655,7 @@ object Scanners { def spaceTabMismatchMsg(lastWidth: IndentWidth, nextWidth: IndentWidth): Message = em"""Incompatible combinations of tabs and spaces in indentation prefixes. |Previous indent : $lastWidth - |Latest indent : $nextWidth""" + |Latest indent : $nextWidth""" def observeColonEOL(inTemplate: Boolean): Unit = val enabled = @@ -670,6 +669,23 @@ object Scanners { reset() if atEOL then token = COLONeol + // consume => and insert if applicable. Used to detect colon arrow: x => + def observeArrowIndented(): Unit = + if isArrow && indentSyntax then + peekAhead() + val atEOL = isAfterLineEnd + val atEOF = token == EOF + reset() + if atEOF then + token = EOF + else if atEOL then + val nextWidth = indentWidth(next.offset) + val lastWidth = currentRegion.indentWidth + if lastWidth < nextWidth then + currentRegion = Indented(nextWidth, COLONeol, currentRegion) + offset = next.offset + token = INDENT + def observeIndented(): Unit = if indentSyntax && isNewLine then val nextWidth = indentWidth(next.offset) @@ -1098,7 +1114,7 @@ object Scanners { reset() next - class LookaheadScanner(val allowIndent: Boolean = false) extends Scanner(source, offset, allowIndent = allowIndent) { + class LookaheadScanner(allowIndent: Boolean = false) extends Scanner(source, offset, allowIndent = allowIndent) { override protected def initialCharBufferSize = 8 override def languageImportContext = Scanner.this.languageImportContext } @@ -1650,7 +1666,7 @@ object Scanners { case class InCase(outer: Region) extends Region(OUTDENT) /** A class describing an indentation region. - * @param width The principal indendation width + * @param width The principal indentation width * @param prefix The token before the initial of the region */ case class Indented(width: IndentWidth, prefix: Token, outer: Region | Null) extends Region(OUTDENT): diff --git a/tests/neg/i22193.scala b/tests/neg/i22193.scala new file mode 100644 index 000000000000..f7ee5b1cf5e1 --- /dev/null +++ b/tests/neg/i22193.scala @@ -0,0 +1,32 @@ + +def fn2(arg: String, arg2: String)(f: String => Unit): Unit = f(arg) + +def fn3(arg: String, arg2: String)(f: => Unit): Unit = f + +def test1() = + + // ok baseline + fn2(arg = "blue sleeps faster than tuesday", arg2 = "the quick brown fox jumped over the lazy dog"): env => + val x = env + println(x) + + fn2( // error not a legal formal parameter for a function literal + arg = "blue sleeps faster than tuesday", + arg2 = "the quick brown fox jumped over the lazy dog"): env => + val x = env // error + println(x) + + fn2( + arg = "blue sleeps faster than tuesday", + arg2 = "the quick brown fox jumped over the lazy dog"): + env => // error indented definitions expected, identifier env found + val x = env + println(x) + +def test2() = + + fn3( // error missing argument list for value of type (=> Unit) => Unit + arg = "blue sleeps faster than tuesday", + arg2 = "the quick brown fox jumped over the lazy dog"): + val x = "Hello" // error + println(x) // error From 5a344b932e5368c4e2dcb52646fe1a1424f4e362 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Tue, 22 Apr 2025 11:44:18 +0200 Subject: [PATCH 085/505] chore: Fix issue with incompatibility with LTS --- .../dotty/tools/dotc/semanticdb/SemanticSymbolBuilder.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/semanticdb/SemanticSymbolBuilder.scala b/compiler/src/dotty/tools/dotc/semanticdb/SemanticSymbolBuilder.scala index 077ee0e40b86..8e7e0ccc2c4b 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/SemanticSymbolBuilder.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/SemanticSymbolBuilder.scala @@ -108,10 +108,12 @@ class SemanticSymbolBuilder: else if (sym.isScala2PackageObject) then b.append(Symbols.PackageObjectDescriptor) else + def isScalaMethodOrVar = sym.isOneOf(Method | Mutable) && !sym.is(JavaDefined) + def isJavaMethod = sym.is(Method) && sym.is(JavaDefined) addName(b, sym.name) if sym.is(Package) then b.append('/') else if sym.isType || sym.isAllOf(JavaModule) then b.append('#') - else if sym.is(Method) || (sym.is(Mutable) && !sym.is(JavaDefined)) + else if (isScalaMethodOrVar || isJavaMethod) && (!sym.is(StableRealizable) || sym.isConstructor) then b.append('('); addOverloadIdx(sym); b.append(").") else b.append('.') From 805eadccc6a576b5b5dd4c3f9a2a45cef78271b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferreira?= Date: Fri, 20 Dec 2024 17:59:20 +0000 Subject: [PATCH 086/505] Use by-name parameter for Properties.*OrElse [Cherry-picked 0dc4b409b5997d9ea13a635f751e05791171c28b] --- .../tools/dotc/config/PathResolver.scala | 3 +- .../dotty/tools/dotc/config/Properties.scala | 6 +-- .../tools/dotc/config/WrappedProperties.scala | 12 ++--- .../tools/dotc/config/PropertiesTest.scala | 45 +++++++++++++++++++ 4 files changed, 55 insertions(+), 11 deletions(-) create mode 100644 compiler/test/dotty/tools/dotc/config/PropertiesTest.scala diff --git a/compiler/src/dotty/tools/dotc/config/PathResolver.scala b/compiler/src/dotty/tools/dotc/config/PathResolver.scala index f60727e6bba2..67be0e3587cb 100644 --- a/compiler/src/dotty/tools/dotc/config/PathResolver.scala +++ b/compiler/src/dotty/tools/dotc/config/PathResolver.scala @@ -53,8 +53,7 @@ object PathResolver { def classPathEnv: String = envOrElse("CLASSPATH", "") def sourcePathEnv: String = envOrElse("SOURCEPATH", "") - //using propOrNone/getOrElse instead of propOrElse so that searchForBootClasspath is lazy evaluated - def javaBootClassPath: String = propOrNone("sun.boot.class.path") getOrElse searchForBootClasspath + def javaBootClassPath: String = propOrElse("sun.boot.class.path", searchForBootClasspath) def javaExtDirs: String = propOrEmpty("java.ext.dirs") def scalaHome: String = propOrEmpty("scala.home") diff --git a/compiler/src/dotty/tools/dotc/config/Properties.scala b/compiler/src/dotty/tools/dotc/config/Properties.scala index 4ea058d2cca8..610428b0f752 100644 --- a/compiler/src/dotty/tools/dotc/config/Properties.scala +++ b/compiler/src/dotty/tools/dotc/config/Properties.scala @@ -45,7 +45,7 @@ trait PropertiesTrait { def propIsSet(name: String): Boolean = System.getProperty(name) != null def propIsSetTo(name: String, value: String): Boolean = propOrNull(name) == value - def propOrElse(name: String, alt: String): String = System.getProperty(name, alt) + def propOrElse(name: String, alt: => String): String = Option(System.getProperty(name)).getOrElse(alt) def propOrEmpty(name: String): String = propOrElse(name, "") def propOrNull(name: String): String = propOrElse(name, null) def propOrNone(name: String): Option[String] = Option(propOrNull(name)) @@ -53,11 +53,11 @@ trait PropertiesTrait { def setProp(name: String, value: String): String = System.setProperty(name, value) def clearProp(name: String): String = System.clearProperty(name) - def envOrElse(name: String, alt: String): String = Option(System getenv name) getOrElse alt + def envOrElse(name: String, alt: => String): String = Option(System getenv name) getOrElse alt def envOrNone(name: String): Option[String] = Option(System getenv name) // for values based on propFilename - def scalaPropOrElse(name: String, alt: String): String = scalaProps.getProperty(name, alt) + def scalaPropOrElse(name: String, alt: => String): String = scalaProps.getProperty(name, alt) def scalaPropOrEmpty(name: String): String = scalaPropOrElse(name, "") def scalaPropOrNone(name: String): Option[String] = Option(scalaProps.getProperty(name)) diff --git a/compiler/src/dotty/tools/dotc/config/WrappedProperties.scala b/compiler/src/dotty/tools/dotc/config/WrappedProperties.scala index 20304b74c1da..a72830331e9f 100644 --- a/compiler/src/dotty/tools/dotc/config/WrappedProperties.scala +++ b/compiler/src/dotty/tools/dotc/config/WrappedProperties.scala @@ -14,12 +14,12 @@ trait WrappedProperties extends PropertiesTrait { protected def propCategory: String = "wrapped" protected def pickJarBasedOn: Class[?] = this.getClass - override def propIsSet(name: String): Boolean = wrap(super.propIsSet(name)) exists (x => x) - override def propOrElse(name: String, alt: String): String = wrap(super.propOrElse(name, alt)) getOrElse alt - override def setProp(name: String, value: String): String = wrap(super.setProp(name, value)).orNull - override def clearProp(name: String): String = wrap(super.clearProp(name)).orNull - override def envOrElse(name: String, alt: String): String = wrap(super.envOrElse(name, alt)) getOrElse alt - override def envOrNone(name: String): Option[String] = wrap(super.envOrNone(name)).flatten + override def propIsSet(name: String): Boolean = wrap(super.propIsSet(name)) exists (x => x) + override def propOrElse(name: String, alt: => String): String = wrap(super.propOrElse(name, alt)) getOrElse alt + override def setProp(name: String, value: String): String = wrap(super.setProp(name, value)).orNull + override def clearProp(name: String): String = wrap(super.clearProp(name)).orNull + override def envOrElse(name: String, alt: => String): String = wrap(super.envOrElse(name, alt)) getOrElse alt + override def envOrNone(name: String): Option[String] = wrap(super.envOrNone(name)).flatten def systemProperties: Iterator[(String, String)] = { import scala.jdk.CollectionConverters.* diff --git a/compiler/test/dotty/tools/dotc/config/PropertiesTest.scala b/compiler/test/dotty/tools/dotc/config/PropertiesTest.scala new file mode 100644 index 000000000000..e45ac1f3983f --- /dev/null +++ b/compiler/test/dotty/tools/dotc/config/PropertiesTest.scala @@ -0,0 +1,45 @@ +package dotty.tools.dotc.config + +import org.junit.Before +import org.junit.Test +import org.junit.Assert._ +import scala.language.unsafeNulls + +class PropertiesTest { + final val TestProperty = "dotty.tools.dotc.config.PropertiesTest.__test_property__" + + @Before + def beforeEach(): Unit = { + Properties.clearProp(TestProperty) + } + + @Test + def testPropOrNone(): Unit = { + assertEquals(Properties.propOrNone(TestProperty), None) + + Properties.setProp(TestProperty, "foo") + + assertEquals(Properties.propOrNone(TestProperty), Some("foo")) + } + + @Test + def testPropOrElse(): Unit = { + assertEquals(Properties.propOrElse(TestProperty, "bar"), "bar") + + Properties.setProp(TestProperty, "foo") + + var done = false + assertEquals(Properties.propOrElse(TestProperty, { done = true; "bar" }), "foo") + assertFalse("Does not evaluate alt if not needed", done) + } + + @Test + def testEnvOrElse(): Unit = { + assertEquals(Properties.envOrElse("_PropertiesTest_NOT_DEFINED", "test"), "test") + + var done = false + val envName = System.getenv().keySet().iterator().next() + assertNotEquals(Properties.envOrElse(envName, {done = true; "bar"}), "bar") + assertFalse("Does not evaluate alt if not needed", done) + } +} From b9124825ec32b60998e107e6b075052d29faae9d Mon Sep 17 00:00:00 2001 From: Matt Bovel Date: Fri, 14 Feb 2025 15:47:54 +0100 Subject: [PATCH 087/505] Add regression test for #22076 (#22602) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #22076. --------- Co-authored-by: Sébastien Doeraene [Cherry-picked a601e83dffd1d1239c295eb5d50e0d4b93412b91] --- tests/pos/match-type-disjoint-22076.scala | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 tests/pos/match-type-disjoint-22076.scala diff --git a/tests/pos/match-type-disjoint-22076.scala b/tests/pos/match-type-disjoint-22076.scala new file mode 100644 index 000000000000..c10555501b97 --- /dev/null +++ b/tests/pos/match-type-disjoint-22076.scala @@ -0,0 +1,8 @@ +trait Foo[CP <: NonEmptyTuple]: + type EndNode = Tuple.Last[CP] + +def f(end: Foo[?]): end.EndNode = + ??? + +trait Bar[CP <: NonEmptyTuple] extends Foo[CP]: + val v: EndNode = f(this) From e1fe8f3e67f2a9c9924a89547cecac9d0b74a0ad Mon Sep 17 00:00:00 2001 From: Matt Bovel Date: Mon, 13 Jan 2025 17:27:18 +0000 Subject: [PATCH 088/505] Avoid infinite recursion when looking for import suggestions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martin Odersky Co-authored-by: Ondřej Lhoták Co-authored-by: Nguyen Pham [Cherry-picked a2412d8d0ebaf4d338502c0c61917229f1a3fb8c] --- .../tools/dotc/typer/ImportSuggestions.scala | 47 ++++++++++--------- tests/neg/22145.check | 4 ++ tests/neg/22145.scala | 8 ++++ tests/neg/22145b.check | 36 ++++++++++++++ tests/neg/22145b.scala | 40 ++++++++++++++++ tests/neg/22145c.check | 4 ++ tests/neg/22145c.scala | 8 ++++ tests/neg/22145d.check | 9 ++++ tests/neg/22145d.scala | 10 ++++ tests/neg/22145e.check | 9 ++++ tests/neg/22145e.scala | 11 +++++ tests/neg/22145f.check | 10 ++++ tests/neg/22145f.scala | 11 +++++ tests/neg/22145g.check | 4 ++ tests/neg/22145g.scala | 10 ++++ 15 files changed, 199 insertions(+), 22 deletions(-) create mode 100644 tests/neg/22145.check create mode 100644 tests/neg/22145.scala create mode 100644 tests/neg/22145b.check create mode 100644 tests/neg/22145b.scala create mode 100644 tests/neg/22145c.check create mode 100644 tests/neg/22145c.scala create mode 100644 tests/neg/22145d.check create mode 100644 tests/neg/22145d.scala create mode 100644 tests/neg/22145e.check create mode 100644 tests/neg/22145e.scala create mode 100644 tests/neg/22145f.check create mode 100644 tests/neg/22145f.scala create mode 100644 tests/neg/22145g.check create mode 100644 tests/neg/22145g.scala diff --git a/compiler/src/dotty/tools/dotc/typer/ImportSuggestions.scala b/compiler/src/dotty/tools/dotc/typer/ImportSuggestions.scala index 1c30f44c29cf..20a48edba757 100644 --- a/compiler/src/dotty/tools/dotc/typer/ImportSuggestions.scala +++ b/compiler/src/dotty/tools/dotc/typer/ImportSuggestions.scala @@ -68,7 +68,7 @@ trait ImportSuggestions: && !(root.name == nme.raw.BAR && ctx.settings.scalajs.value && root == JSDefinitions.jsdefn.PseudoUnionModule) } - def nestedRoots(site: Type)(using Context): List[Symbol] = + def nestedRoots(site: Type, parentSymbols: Set[Symbol])(using Context): List[Symbol] = val seenNames = mutable.Set[Name]() site.baseClasses.flatMap { bc => bc.info.decls.filter { dcl => @@ -78,34 +78,37 @@ trait ImportSuggestions: } } - def rootsStrictlyIn(ref: Type)(using Context): List[TermRef] = + def rootsStrictlyIn(ref: Type, parentSymbols: Set[Symbol] = Set())(using Context): List[TermRef] = val site = ref.widen val refSym = site.typeSymbol - val nested = - if refSym.is(Package) then - if refSym == defn.EmptyPackageClass // Don't search the empty package - || refSym == defn.JavaPackageClass // As an optimization, don't search java... - || refSym == defn.JavaLangPackageClass // ... or java.lang. - then Nil - else refSym.info.decls.filter(lookInside) - else if refSym.infoOrCompleter.isInstanceOf[StubInfo] then - Nil // Don't chase roots that do not exist - else - if !refSym.is(Touched) then - refSym.ensureCompleted() // JavaDefined is reliably known only after completion - if refSym.is(JavaDefined) then Nil - else nestedRoots(site) - nested - .map(mbr => TermRef(ref, mbr.asTerm)) - .flatMap(rootsIn) - .toList + if parentSymbols.contains(refSym) then Nil + else + val nested = + if refSym.is(Package) then + if refSym == defn.EmptyPackageClass // Don't search the empty package + || refSym == defn.JavaPackageClass // As an optimization, don't search java... + || refSym == defn.JavaLangPackageClass // ... or java.lang. + then Nil + else refSym.info.decls.filter(lookInside) + else if refSym.infoOrCompleter.isInstanceOf[StubInfo] then + Nil // Don't chase roots that do not exist + else + if !refSym.is(Touched) then + refSym.ensureCompleted() // JavaDefined is reliably known only after completion + if refSym.is(JavaDefined) then Nil + else nestedRoots(site, parentSymbols) + val newParentSymbols = parentSymbols + refSym + nested + .map(mbr => TermRef(ref, mbr.asTerm)) + .flatMap(rootsIn(_, newParentSymbols)) + .toList - def rootsIn(ref: TermRef)(using Context): List[TermRef] = + def rootsIn(ref: TermRef, parentSymbols: Set[Symbol] = Set())(using Context): List[TermRef] = if seen.contains(ref) then Nil else implicitsDetailed.println(i"search for suggestions in ${ref.symbol.fullName}") seen += ref - ref :: rootsStrictlyIn(ref) + ref :: rootsStrictlyIn(ref, parentSymbols) def rootsOnPath(tp: Type)(using Context): List[TermRef] = tp match case ref: TermRef => rootsIn(ref) ::: rootsOnPath(ref.prefix) diff --git a/tests/neg/22145.check b/tests/neg/22145.check new file mode 100644 index 000000000000..4592c42e9e7f --- /dev/null +++ b/tests/neg/22145.check @@ -0,0 +1,4 @@ +-- [E008] Not Found Error: tests/neg/22145.scala:5:7 ------------------------------------------------------------------- +5 | base.foo() // error + | ^^^^^^^^ + | value foo is not a member of foo.Collection diff --git a/tests/neg/22145.scala b/tests/neg/22145.scala new file mode 100644 index 000000000000..59d58b167ab4 --- /dev/null +++ b/tests/neg/22145.scala @@ -0,0 +1,8 @@ +package foo + +trait Collection: + val base: Collection = ??? + base.foo() // error + + object O extends Collection: + def foo(): Int = ??? diff --git a/tests/neg/22145b.check b/tests/neg/22145b.check new file mode 100644 index 000000000000..de605ce24276 --- /dev/null +++ b/tests/neg/22145b.check @@ -0,0 +1,36 @@ +-- [E008] Not Found Error: tests/neg/22145b.scala:15:19 ---------------------------------------------------------------- +15 | require(base.isWithin(p, start, end), "position is out of bounds") // error + | ^^^^^^^^^^^^^ + | value isWithin is not a member of Collection.this.Self +-- [E008] Not Found Error: tests/neg/22145b.scala:28:59 ---------------------------------------------------------------- +28 | def positionAfter(p: Position): Position = self.base.positionAfter(p) // error + | ^^^^^^^^^^^^^^^^^^^^^^^ + |value positionAfter is not a member of Collection.this.Self. + |An extension method was tried, but could not be fully constructed: + | + | this.positionAfter(self.base) + | + | failed with: + | + | Found: (self.base : Collection.this.Self) + | Required: foo.Collection.given_is_Slice_Collection.Self² + | + | where: Self is a type in trait Collection + | Self² is a type in object given_is_Slice_Collection which is an alias of Collection.this.Slice + | +-- [E008] Not Found Error: tests/neg/22145b.scala:29:50 ---------------------------------------------------------------- +29 | def apply(p: Position): Element = self.base.apply(p) // error + | ^^^^^^^^^^^^^^^ + |value apply is not a member of Collection.this.Self. + |An extension method was tried, but could not be fully constructed: + | + | this.apply(self.base) + | + | failed with: + | + | Found: (self.base : Collection.this.Self) + | Required: foo.Collection.given_is_Slice_Collection.Self² + | + | where: Self is a type in trait Collection + | Self² is a type in object given_is_Slice_Collection which is an alias of Collection.this.Slice + | diff --git a/tests/neg/22145b.scala b/tests/neg/22145b.scala new file mode 100644 index 000000000000..5b8de5672fba --- /dev/null +++ b/tests/neg/22145b.scala @@ -0,0 +1,40 @@ +package foo + +import language.experimental.modularity + +trait Collection: + me => + + type Self + type Position + type Element + + final class Slice(private[Collection] val base: Self, val start: Position, val end: Position): + + final def apply(p: Position): Element = + require(base.isWithin(p, start, end), "position is out of bounds") // error + base.apply(p) + + end Slice + + given Slice is Collection: + + type Position = me.Position + type Element = me.Element + + extension (self: Self) + def start: Position = self.start + def end: Position = self.end + def positionAfter(p: Position): Position = self.base.positionAfter(p) // error + def apply(p: Position): Element = self.base.apply(p) // error + + end given + + extension (self: Self) + + def start: Position + def end: Position + def positionAfter(p: Position): Position + def apply(p: Position): Element + + end extension diff --git a/tests/neg/22145c.check b/tests/neg/22145c.check new file mode 100644 index 000000000000..ddfb6b9daf1d --- /dev/null +++ b/tests/neg/22145c.check @@ -0,0 +1,4 @@ +-- [E008] Not Found Error: tests/neg/22145c.scala:4:35 ----------------------------------------------------------------- +4 | def bar(base: Collection) = base.foo // error + | ^^^^^^^^ + | value foo is not a member of foo.Collection diff --git a/tests/neg/22145c.scala b/tests/neg/22145c.scala new file mode 100644 index 000000000000..7776e57e7906 --- /dev/null +++ b/tests/neg/22145c.scala @@ -0,0 +1,8 @@ +package foo + +trait Collection: + def bar(base: Collection) = base.foo // error + object a extends Collection: + def foo: Int = 0 + object b extends Collection: + def foo: Int = 1 diff --git a/tests/neg/22145d.check b/tests/neg/22145d.check new file mode 100644 index 000000000000..ac6469c10b82 --- /dev/null +++ b/tests/neg/22145d.check @@ -0,0 +1,9 @@ +-- [E008] Not Found Error: tests/neg/22145d.scala:10:4 ----------------------------------------------------------------- +10 | 2.f() // error + | ^^^ + | value f is not a member of Int, but could be made available as an extension method. + | + | The following import might fix the problem: + | + | import foo.O2.f + | diff --git a/tests/neg/22145d.scala b/tests/neg/22145d.scala new file mode 100644 index 000000000000..bfb68e088322 --- /dev/null +++ b/tests/neg/22145d.scala @@ -0,0 +1,10 @@ +package foo + +class C[T]: + extension (x: T) def f(): Int = 1 + +object O1 extends C[String] +object O2 extends C[Int] + +def main = + 2.f() // error diff --git a/tests/neg/22145e.check b/tests/neg/22145e.check new file mode 100644 index 000000000000..e1c34e59f239 --- /dev/null +++ b/tests/neg/22145e.check @@ -0,0 +1,9 @@ +-- [E008] Not Found Error: tests/neg/22145e.scala:11:4 ----------------------------------------------------------------- +11 | 2.f() // error + | ^^^ + | value f is not a member of Int, but could be made available as an extension method. + | + | The following import might fix the problem: + | + | import foo.O2.Ext.f + | diff --git a/tests/neg/22145e.scala b/tests/neg/22145e.scala new file mode 100644 index 000000000000..579fd65c685e --- /dev/null +++ b/tests/neg/22145e.scala @@ -0,0 +1,11 @@ +package foo + +class C[T]: + object Ext: + extension (x: T) def f(): Int = 1 + +object O1 extends C[String] +object O2 extends C[Int] + +def main = + 2.f() // error diff --git a/tests/neg/22145f.check b/tests/neg/22145f.check new file mode 100644 index 000000000000..b870eb21057a --- /dev/null +++ b/tests/neg/22145f.check @@ -0,0 +1,10 @@ +-- [E008] Not Found Error: tests/neg/22145f.scala:11:6 ----------------------------------------------------------------- +11 | 2.f() // error + | ^^^ + | value f is not a member of Int, but could be made available as an extension method. + | + | One of the following imports might fix the problem: + | + | import C.this.O1.O2.Ext.f + | import C.this.O2.Ext.f + | diff --git a/tests/neg/22145f.scala b/tests/neg/22145f.scala new file mode 100644 index 000000000000..97f1336d1b1b --- /dev/null +++ b/tests/neg/22145f.scala @@ -0,0 +1,11 @@ +package foo + +class C[T]: + object Ext: + extension (x: T) def f(): Int = 1 + + object O1 extends C[String] + object O2 extends C[Int] + + def g = + 2.f() // error diff --git a/tests/neg/22145g.check b/tests/neg/22145g.check new file mode 100644 index 000000000000..175949ac113f --- /dev/null +++ b/tests/neg/22145g.check @@ -0,0 +1,4 @@ +-- [E008] Not Found Error: tests/neg/22145g.scala:10:4 ----------------------------------------------------------------- +10 | 2.f() // error + | ^^^ + | value f is not a member of Int diff --git a/tests/neg/22145g.scala b/tests/neg/22145g.scala new file mode 100644 index 000000000000..8b888516c044 --- /dev/null +++ b/tests/neg/22145g.scala @@ -0,0 +1,10 @@ +package foo + +class C[T]: + extension (x: T) def f(): Int = 1 + +object O: + val c0: C[String] = new C[String] + val c1: C[Int] = new C[Int] + // Currently no import suggestions here + 2.f() // error From 4c91a0bf9d54fe4490f9992354b98605a3bec6c4 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Fri, 14 Feb 2025 10:01:21 +0000 Subject: [PATCH 089/505] Avoid crash in uninhab check in Space [Cherry-picked 899d4078a0d83ccdd8663a4ff11f79b1350e8a8e] --- .../src/dotty/tools/dotc/transform/patmat/Space.scala | 2 +- tests/pos/i22518.scala | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 tests/pos/i22518.scala diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index 9cf94877328b..8f015bcd5f42 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -655,7 +655,7 @@ object SpaceEngine { val superType = child.typeRef.superType if typeArgs.exists(_.isBottomType) && superType.isInstanceOf[ClassInfo] then val parentClass = superType.asInstanceOf[ClassInfo].declaredParents.find(_.classSymbol == parent).get - val paramTypeMap = Map.from(parentClass.argTypes.map(_.typeSymbol).zip(typeArgs)) + val paramTypeMap = Map.from(parentClass.argInfos.map(_.typeSymbol).zip(typeArgs)) val substArgs = child.typeRef.typeParamSymbols.map(param => paramTypeMap.getOrElse(param, WildcardType)) substArgs else Nil diff --git a/tests/pos/i22518.scala b/tests/pos/i22518.scala new file mode 100644 index 000000000000..d530159701c4 --- /dev/null +++ b/tests/pos/i22518.scala @@ -0,0 +1,9 @@ +sealed trait Foo[T] +class Bar extends Foo[?] + +def mkFoo[T]: Foo[T] = + ??? + +def test: Unit = + mkFoo match + case _ => () From 65bc5aa5c6997f1326d8d8430f0d24a82c09b33a Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Fri, 24 Jan 2025 18:26:13 +0100 Subject: [PATCH 090/505] fix: treat static vals as enclosures in lambdalift [Cherry-picked f52782e315256b54639c01ed7a041cf790a4aeb9] --- .../src/dotty/tools/dotc/core/SymDenotations.scala | 9 +++++++++ .../src/dotty/tools/dotc/transform/LambdaLift.scala | 4 ++-- tests/pos/i22408.scala | 11 +++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 tests/pos/i22408.scala diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index c26d8c320897..0e068eff2cfd 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1218,6 +1218,15 @@ object SymDenotations { else if (this.exists) owner.enclosingMethod else NoSymbol + /** The closest enclosing method or static symbol containing this definition. + * A local dummy owner is mapped to the primary constructor of the class. + */ + final def enclosingMethodOrStatic(using Context): Symbol = + if this.is(Method) || this.hasAnnotation(defn.ScalaStaticAnnot) then symbol + else if this.isClass then primaryConstructor + else if this.exists then owner.enclosingMethodOrStatic + else NoSymbol + /** The closest enclosing extension method containing this definition, * including methods outside the current class. */ diff --git a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala index 3fbdf1fa5427..12045be7419a 100644 --- a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala +++ b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala @@ -34,8 +34,8 @@ object LambdaLift: val liftedDefs: HashMap[Symbol, ListBuffer[Tree]] = new HashMap val deps = new Dependencies(ctx.compilationUnit.tpdTree, ctx.withPhase(thisPhase)): - def isExpr(sym: Symbol)(using Context): Boolean = sym.is(Method) - def enclosure(using Context) = ctx.owner.enclosingMethod + def isExpr(sym: Symbol)(using Context): Boolean = sym.is(Method) || sym.hasAnnotation(defn.ScalaStaticAnnot) + def enclosure(using Context) = ctx.owner.enclosingMethodOrStatic override def process(tree: Tree)(using Context): Unit = super.process(tree) diff --git a/tests/pos/i22408.scala b/tests/pos/i22408.scala new file mode 100644 index 000000000000..17fd0fbb474d --- /dev/null +++ b/tests/pos/i22408.scala @@ -0,0 +1,11 @@ +object Obj: + @scala.annotation.static + val some_static_value: Int = { + val some_local_value: Int = { + val some_local_value_1 = ??? + some_local_value_1 + } + some_local_value + } + +class Obj From 9f5e2b54fe07d717bd6e51a4c7271e4d3198ab4c Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Sun, 9 Feb 2025 01:20:29 -0800 Subject: [PATCH 091/505] Constructor proxy or companion is as protected as class Require the constructor companion to be protected if the class is; or create it protected. Otherwise, create protected proxies. --- .../src/dotty/tools/dotc/core/NamerOps.scala | 8 +++++-- .../dotty/tools/dotc/typer/Applications.scala | 3 +-- .../src/dotty/tools/dotc/typer/Typer.scala | 6 ++--- tests/neg/i22560.scala | 22 +++++++++++++++++++ tests/neg/i22560b.scala | 9 ++++++++ tests/pos/i22560.scala | 22 +++++++++++++++++++ 6 files changed, 63 insertions(+), 7 deletions(-) create mode 100644 tests/neg/i22560.scala create mode 100644 tests/neg/i22560b.scala create mode 100644 tests/pos/i22560.scala diff --git a/compiler/src/dotty/tools/dotc/core/NamerOps.scala b/compiler/src/dotty/tools/dotc/core/NamerOps.scala index e4364d168267..7129527fb22a 100644 --- a/compiler/src/dotty/tools/dotc/core/NamerOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NamerOps.scala @@ -110,8 +110,10 @@ object NamerOps: */ def addConstructorApplies(scope: MutableScope, cls: ClassSymbol, modcls: ClassSymbol)(using Context): scope.type = def proxy(constr: Symbol): Symbol = + var flags = ApplyProxyFlags | (constr.flagsUNSAFE & AccessFlags) + if cls.is(Protected) && !modcls.is(Protected) then flags |= Protected newSymbol( - modcls, nme.apply, ApplyProxyFlags | (constr.flagsUNSAFE & AccessFlags), + modcls, nme.apply, flags, ApplyProxyCompleter(constr), coord = constr.coord) for dcl <- cls.info.decls do if dcl.isConstructor then scope.enter(proxy(dcl)) @@ -133,9 +135,11 @@ object NamerOps: /** A new symbol that is the constructor companion for class `cls` */ def classConstructorCompanion(cls: ClassSymbol)(using Context): TermSymbol = + var flags = ConstructorCompanionFlags + if cls.is(Protected) then flags |= Protected val companion = newModuleSymbol( cls.owner, cls.name.toTermName, - ConstructorCompanionFlags, ConstructorCompanionFlags, + flags, flags, constructorCompanionCompleter(cls), coord = cls.coord, assocFile = cls.assocFile) diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 1e6fbd7bed17..5254ec3712c1 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -1111,9 +1111,8 @@ trait Applications extends Compatibility { // // summonFrom { // case given A[t] => - // summonFrom + // summonFrom: // case given `t` => ... - // } // } // // the second `summonFrom` should expand only once the first `summonFrom` is diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 38bc6960e370..42a0c24c9f24 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -3821,9 +3821,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer readapt(tree.appliedToNone) // insert () to primary constructors else errorTree(tree, em"Missing arguments for $methodStr") - case _ => tryInsertApplyOrImplicit(tree, pt, locked) { - errorTree(tree, MethodDoesNotTakeParameters(tree)) - } + case _ => + tryInsertApplyOrImplicit(tree, pt, locked): + errorTree(tree, MethodDoesNotTakeParameters(tree)) } def adaptNoArgsImplicitMethod(wtp: MethodType): Tree = { diff --git a/tests/neg/i22560.scala b/tests/neg/i22560.scala new file mode 100644 index 000000000000..2957ac4a1bf1 --- /dev/null +++ b/tests/neg/i22560.scala @@ -0,0 +1,22 @@ + +class A: + protected class B + +// This fails to compile, as expected +val x = A().B() // error + +object C: + protected val p = "protected" + protected def getString() = "Hello!" + protected class D: + def d = D() // ok + +// This fails to compile +// val y = C.p + +// And this also fails to compile +// val z = C.getString() + +// However, this compiles just fine. +val alpha = C.D() // error +val beta = new C.D() // error diff --git a/tests/neg/i22560b.scala b/tests/neg/i22560b.scala new file mode 100644 index 000000000000..0a906832f2b3 --- /dev/null +++ b/tests/neg/i22560b.scala @@ -0,0 +1,9 @@ + +class Enumeration: + protected class Val(i: Int): + def this() = this(42) + object Val + +class Test extends Enumeration: + val Hearts = Val(27) // error + val Diamonds = Val() // error diff --git a/tests/pos/i22560.scala b/tests/pos/i22560.scala new file mode 100644 index 000000000000..947923aba259 --- /dev/null +++ b/tests/pos/i22560.scala @@ -0,0 +1,22 @@ + +package companionless: + + class Enumeration: + protected class Val(i: Int): + def this() = this(42) + + class Test extends Enumeration: + val Hearts = Val(27) + val Diamonds = Val() + + +package companioned: + + class Enumeration: + protected class Val(i: Int): + def this() = this(42) + protected object Val + + class Test extends Enumeration: + val Hearts = Val(27) + val Diamonds = Val() From ed37fe0d1d1e2ca303f5864a97645d3f6ba00674 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Tue, 22 Apr 2025 15:43:02 +0200 Subject: [PATCH 092/505] Constructor proxy or companion is as protected as class Require the constructor companion to be protected if the class is; or create it protected. Otherwise, create protected proxies. [Cherry-picked fddab10b57bacef6891dc6f169a238a80d232b1d][modified] From ca09ca79b23f62eacf80e27d594d8f322aa3da10 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Thu, 13 Feb 2025 09:30:58 -0800 Subject: [PATCH 093/505] Reference on access of ctor proxy [Cherry-picked b6ad24f21798fe0d148deea276e23c3226fd68f1] --- .../reference/other-new-features/creator-applications.md | 7 +++++-- tests/neg/i22560b.scala | 9 +++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/docs/_docs/reference/other-new-features/creator-applications.md b/docs/_docs/reference/other-new-features/creator-applications.md index 8b1de02b2f25..f3b58b87bc48 100644 --- a/docs/_docs/reference/other-new-features/creator-applications.md +++ b/docs/_docs/reference/other-new-features/creator-applications.md @@ -39,8 +39,11 @@ The precise rules are as follows: - the class has a companion object (which might have been generated in step 1), and - that companion object does not already define a member named `apply`. - Each generated `apply` method forwards to one constructor of the class. It has the - same type and value parameters as the constructor. + Each generated `apply` method forwards to one constructor of the class. + It has the same type and value parameters as the constructor, + as well as the same access restriction as the class. + If the class is `protected`, then either the companion object must be `protected` + or the `apply` method will be made `protected`. Constructor proxy companions cannot be used as values by themselves. A proxy companion object must be selected with `apply` (or be applied to arguments, in which case the `apply` is implicitly diff --git a/tests/neg/i22560b.scala b/tests/neg/i22560b.scala index 0a906832f2b3..bce079e0eeb2 100644 --- a/tests/neg/i22560b.scala +++ b/tests/neg/i22560b.scala @@ -7,3 +7,12 @@ class Enumeration: class Test extends Enumeration: val Hearts = Val(27) // error val Diamonds = Val() // error + +package p: + private[p] class C(i: Int) // ctor proxy gets privateWithin of class + private[p] class D(i: Int) + object D + +package q: + def f() = p.C(42) // error + def g() = p.D(42) // error From ac5c0db63b51e51c0c01182be70924c086cfaddc Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Mon, 17 Feb 2025 09:56:53 -0800 Subject: [PATCH 094/505] Clarify reference on inferred object-private parameter [Cherry-picked 7aca1280b78a794afee160ca6bb83a05e5042a71] --- .../reference/dropped-features/this-qualifier.md | 12 ++++++++++++ tests/neg/i22620.scala | 4 ++++ 2 files changed, 16 insertions(+) create mode 100644 tests/neg/i22620.scala diff --git a/docs/_docs/reference/dropped-features/this-qualifier.md b/docs/_docs/reference/dropped-features/this-qualifier.md index f75d19356696..541c91e5cdfa 100644 --- a/docs/_docs/reference/dropped-features/this-qualifier.md +++ b/docs/_docs/reference/dropped-features/this-qualifier.md @@ -29,3 +29,15 @@ This can cause problems if a program tries to access the missing private field v // [C] needed if `field` is to be accessed through reflection val retained = field * field ``` + +Class parameters are normally inferred object-private, +so that members introduced by explicitly declaring them `val` or `var` are exempt from the rule described here. + +In particular, the following field is not excluded from variance checking: +```scala + class C[-T](private val t: T) // error +``` +And in contrast to the private field shown above, this field is not eliminated: +```scala + class C(private val c: Int) +``` diff --git a/tests/neg/i22620.scala b/tests/neg/i22620.scala new file mode 100644 index 000000000000..97d1d55e3302 --- /dev/null +++ b/tests/neg/i22620.scala @@ -0,0 +1,4 @@ + +import scala.collection.mutable.ArrayBuffer + +class PrivateTest[-M](private val v: ArrayBuffer[M]) // error From b71066aeda345b583fbcc5c9e6055662622382da Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Sat, 15 Feb 2025 14:32:39 -0800 Subject: [PATCH 095/505] Allow observing an indent after conditional Normally do not infer NEWLINE within parens, but special case old syntax for conditionals, so that it can observe indented syntax. The mechanism is to inject an Indented region when parsing a parenthesized condition which is within an InParens region, such as an arg list. The effect is not to advance past EOL after `(true)`. [Cherry-picked 4ba89e9e8eb027b2bd11503e3621fa5e62e7bad0] --- .../dotty/tools/dotc/parsing/Parsers.scala | 9 +++- tests/pos/i22608.scala | 48 +++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 tests/pos/i22608.scala diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 4354be9662be..63acae33be43 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -97,6 +97,9 @@ object Parsers { private val InCase: Region => Region = Scanners.InCase(_) private val InCond: Region => Region = Scanners.InParens(LPAREN, _) private val InFor : Region => Region = Scanners.InBraces(_) + private val InBrk : Region => Region = _.match + case p: Scanners.InParens => Scanners.Indented(p.indentWidth, p.prefix, p) + case r => r abstract class ParserCommon(val source: SourceFile)(using Context) { @@ -2129,8 +2132,10 @@ object Parsers { def condExpr(altToken: Token): Tree = val t: Tree = if in.token == LPAREN then - var t: Tree = atSpan(in.offset): - makeTupleOrParens(inParensWithCommas(commaSeparated(exprInParens))) + var t: Tree = + inSepRegion(InBrk): // allow inferred NEWLINE for observeIndented below + atSpan(in.offset): + makeTupleOrParens(inParensWithCommas(commaSeparated(exprInParens))) if in.token != altToken then if toBeContinued(altToken) then t = inSepRegion(InCond) { diff --git a/tests/pos/i22608.scala b/tests/pos/i22608.scala new file mode 100644 index 000000000000..e4b49e87769f --- /dev/null +++ b/tests/pos/i22608.scala @@ -0,0 +1,48 @@ + +def f(i: Int) = i +def g(i: Int, j: Int) = i+j + +def t = + val y = f( + if (true)// then + val x = 1 + 5 + else 7 + ) + y + +def u(j: Int) = + val y = g( + if (true)// then + val x = 1 + 5 + else 7, + j + ) + y + +def b(k: Boolean): Int = + f( + if ( + k + && b(!k) > 0 + ) then 27 + else 42 + ) + +def p(b: Boolean) = + import collection.mutable.ListBuffer + val xs, ys = ListBuffer.empty[String] + (if (b) + xs + else + ys) += "hello, world" + (xs.toString, ys.toString) + +def q(b: Boolean) = + import collection.mutable.ListBuffer + val xs, ys = ListBuffer.empty[String] + (if (b) + then xs + else ys) += "hello, world" + (xs.toString, ys.toString) From 1e9068ebd39aa13e998b8bdb7491928d500c5cec Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Sun, 16 Feb 2025 08:49:08 -0800 Subject: [PATCH 096/505] Prefer chaining, avoid duplication in finally [Cherry-picked c8131c031a644c2f9d0dcd9f5fb9f07889880657] --- .../dotty/tools/dotc/parsing/Parsers.scala | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 63acae33be43..2a2acc84d7b4 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -97,7 +97,7 @@ object Parsers { private val InCase: Region => Region = Scanners.InCase(_) private val InCond: Region => Region = Scanners.InParens(LPAREN, _) private val InFor : Region => Region = Scanners.InBraces(_) - private val InBrk : Region => Region = _.match + private val InBrk : Region => Region = case p: Scanners.InParens => Scanners.Indented(p.indentWidth, p.prefix, p) case r => r @@ -2132,27 +2132,25 @@ object Parsers { def condExpr(altToken: Token): Tree = val t: Tree = if in.token == LPAREN then - var t: Tree = - inSepRegion(InBrk): // allow inferred NEWLINE for observeIndented below - atSpan(in.offset): - makeTupleOrParens(inParensWithCommas(commaSeparated(exprInParens))) - if in.token != altToken then - if toBeContinued(altToken) then - t = inSepRegion(InCond) { + inSepRegion(InBrk): // allow inferred NEWLINE for observeIndented below + atSpan(in.offset): + makeTupleOrParens(inParensWithCommas(commaSeparated(exprInParens))) + .pipe: t => + if in.token == altToken then t + else if toBeContinued(altToken) then + inSepRegion(InCond): expr1Rest( postfixExprRest( simpleExprRest(t, Location.ElseWhere), Location.ElseWhere), Location.ElseWhere) - } else if rewriteToNewSyntax(t.span) then - dropParensOrBraces(t.span.start, s"${tokenString(altToken)}") + dropParensOrBraces(t.span.start, tokenString(altToken)) in.observeIndented() return t - t else if in.isNestedStart then - try expr() finally newLinesOpt() + expr().tap(_ => newLinesOpt()) else inSepRegion(InCond)(expr()) if rewriteToOldSyntax(t.span.startPos) then revertToParens(t) From bb8eb471d423e98b629216fbca54f4ce90d28f85 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Tue, 18 Feb 2025 09:18:01 -0800 Subject: [PATCH 097/505] Clarify region workaround [Cherry-picked a19c14ad704c4d1d2e2e794c888fecf8672b0797] --- compiler/src/dotty/tools/dotc/parsing/Parsers.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 2a2acc84d7b4..47389fbce054 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -97,7 +97,7 @@ object Parsers { private val InCase: Region => Region = Scanners.InCase(_) private val InCond: Region => Region = Scanners.InParens(LPAREN, _) private val InFor : Region => Region = Scanners.InBraces(_) - private val InBrk : Region => Region = + private val InOldCond: Region => Region = // old-style Cond to allow indent when InParens, see #22608 case p: Scanners.InParens => Scanners.Indented(p.indentWidth, p.prefix, p) case r => r @@ -2132,7 +2132,7 @@ object Parsers { def condExpr(altToken: Token): Tree = val t: Tree = if in.token == LPAREN then - inSepRegion(InBrk): // allow inferred NEWLINE for observeIndented below + inSepRegion(InOldCond): // allow inferred NEWLINE for observeIndented below atSpan(in.offset): makeTupleOrParens(inParensWithCommas(commaSeparated(exprInParens))) .pipe: t => From c20c16d77d54e2e1e4382141103ab0b6e47b9771 Mon Sep 17 00:00:00 2001 From: Jan Chyb Date: Mon, 17 Feb 2025 15:30:42 +0100 Subject: [PATCH 098/505] Fix issue with static `this` references erroring in quoted code Previously, inherited methods, even if accessed via static objects, were not able to be used in quotations, unless explicitly pointed to with a non-`this` prefix. This was due to the fact that during the cross-stage safety check, first the method itself was checked for if it was static (which for the inherited method, it was not), and if not, the prefix was checked further, erroring on any `this` tree found along the way. This was fixed by allowing `this` trees if they point to static objects. This way not only is the initial issue fixed, but also we are able to freely reference static methods with `this`, like '{this.objectMethod} (whereas previously, only '{Object.objectMethod} or '{objectMethod} were allowed, despite them all pointing to the same static method). [Cherry-picked 71ddfb5f628b3d5c9b02d187f8fbbf6c03147283] --- .../tools/dotc/staging/CrossStageSafety.scala | 10 +++++++++- tests/neg/i22592.scala | 14 ++++++++++++++ tests/pos/i22592.scala | 15 +++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tests/neg/i22592.scala create mode 100644 tests/pos/i22592.scala diff --git a/compiler/src/dotty/tools/dotc/staging/CrossStageSafety.scala b/compiler/src/dotty/tools/dotc/staging/CrossStageSafety.scala index 1832eeabca7e..4534af0f0883 100644 --- a/compiler/src/dotty/tools/dotc/staging/CrossStageSafety.scala +++ b/compiler/src/dotty/tools/dotc/staging/CrossStageSafety.scala @@ -189,11 +189,19 @@ class CrossStageSafety extends TreeMapWithStages { /** Check level consistency of terms references */ private def checkLevelConsistency(tree: Ident | This)(using Context): Unit = + def isStatic(pre: Type)(using Context): Boolean = pre match + case pre: NamedType => + val sym = pre.currentSymbol + sym.is(Package) || sym.isStaticOwner && isStatic(pre.prefix) + case pre: ThisType => isStatic(pre.tref) + case _ => true new TypeTraverser { def traverse(tp: Type): Unit = tp match case tp @ TermRef(NoPrefix, _) if !tp.symbol.isStatic && level != levelOf(tp.symbol) => levelError(tp.symbol, tp, tree.srcPos) + case tp: ThisType if isStatic(tp) => + // static object (OK) case tp: ThisType if level != -1 && level != levelOf(tp.cls) => levelError(tp.cls, tp, tree.srcPos) case tp: AnnotatedType => @@ -201,7 +209,7 @@ class CrossStageSafety extends TreeMapWithStages { case _ if tp.typeSymbol.is(Package) => // OK case _ => - traverseChildren(tp) + traverseChildren(tp) }.traverse(tree.tpe) private def levelError(sym: Symbol, tp: Type, pos: SrcPos)(using Context): tp.type = { diff --git a/tests/neg/i22592.scala b/tests/neg/i22592.scala new file mode 100644 index 000000000000..6a9a89cacf2a --- /dev/null +++ b/tests/neg/i22592.scala @@ -0,0 +1,14 @@ +import scala.quoted.* + +trait Foo: + def inherited = () + +class Bar extends Foo: + def local = () + def localArg(arg: Any) = () + + def macro1(using Quotes): Expr[Unit] = '{ local } // error + def macro3(using Quotes): Expr[Unit] = '{ inherited } // error + def macro4(using Quotes): Expr[Unit] = '{ this.local } // error + def macro5(using Quotes): Expr[Unit] = '{ this.inherited } // error + def macro6(using Quotes): Expr[Unit] = '{ localArg(this) } // error // error diff --git a/tests/pos/i22592.scala b/tests/pos/i22592.scala new file mode 100644 index 000000000000..f6a1f2eff696 --- /dev/null +++ b/tests/pos/i22592.scala @@ -0,0 +1,15 @@ +import scala.quoted.* + +trait Foo: + def inherited = () + +object Bar extends Foo: + def local = () + def localArg(arg: Any) = () + + def macro1(using Quotes): Expr[Unit] = '{ local } + def macro2(using Quotes): Expr[Unit] = '{ Bar.inherited } + def macro3(using Quotes): Expr[Unit] = '{ inherited } + def macro4(using Quotes): Expr[Unit] = '{ this.local } + def macro5(using Quotes): Expr[Unit] = '{ this.inherited } + def macro6(using Quotes): Expr[Unit] = '{ localArg(this) } From 663f8ecdb98528dc43a554467021faf8f031bb2e Mon Sep 17 00:00:00 2001 From: Jan Chyb Date: Mon, 17 Feb 2025 15:30:42 +0100 Subject: [PATCH 099/505] chore: Add @nowarn annotation to LazyVals. (#22270) Unsafe is planned to be removed in future Java versions. Motivication: Makes it compile on JDK 23 refs: https://openjdk.org/jeps/471 Modification: Add `@nowarn("cat=deprecation")` Result: Compiles successfully on JDK 23 [Cherry-picked 4952e0af407d652a47efb5436fe0e0f023db3367] --- .../tools/dotc/staging/CrossStageSafety.scala | 10 +++++++++- tests/neg/i22592.scala | 14 ++++++++++++++ tests/pos/i22592.scala | 15 +++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tests/neg/i22592.scala create mode 100644 tests/pos/i22592.scala diff --git a/compiler/src/dotty/tools/dotc/staging/CrossStageSafety.scala b/compiler/src/dotty/tools/dotc/staging/CrossStageSafety.scala index 1832eeabca7e..4534af0f0883 100644 --- a/compiler/src/dotty/tools/dotc/staging/CrossStageSafety.scala +++ b/compiler/src/dotty/tools/dotc/staging/CrossStageSafety.scala @@ -189,11 +189,19 @@ class CrossStageSafety extends TreeMapWithStages { /** Check level consistency of terms references */ private def checkLevelConsistency(tree: Ident | This)(using Context): Unit = + def isStatic(pre: Type)(using Context): Boolean = pre match + case pre: NamedType => + val sym = pre.currentSymbol + sym.is(Package) || sym.isStaticOwner && isStatic(pre.prefix) + case pre: ThisType => isStatic(pre.tref) + case _ => true new TypeTraverser { def traverse(tp: Type): Unit = tp match case tp @ TermRef(NoPrefix, _) if !tp.symbol.isStatic && level != levelOf(tp.symbol) => levelError(tp.symbol, tp, tree.srcPos) + case tp: ThisType if isStatic(tp) => + // static object (OK) case tp: ThisType if level != -1 && level != levelOf(tp.cls) => levelError(tp.cls, tp, tree.srcPos) case tp: AnnotatedType => @@ -201,7 +209,7 @@ class CrossStageSafety extends TreeMapWithStages { case _ if tp.typeSymbol.is(Package) => // OK case _ => - traverseChildren(tp) + traverseChildren(tp) }.traverse(tree.tpe) private def levelError(sym: Symbol, tp: Type, pos: SrcPos)(using Context): tp.type = { diff --git a/tests/neg/i22592.scala b/tests/neg/i22592.scala new file mode 100644 index 000000000000..6a9a89cacf2a --- /dev/null +++ b/tests/neg/i22592.scala @@ -0,0 +1,14 @@ +import scala.quoted.* + +trait Foo: + def inherited = () + +class Bar extends Foo: + def local = () + def localArg(arg: Any) = () + + def macro1(using Quotes): Expr[Unit] = '{ local } // error + def macro3(using Quotes): Expr[Unit] = '{ inherited } // error + def macro4(using Quotes): Expr[Unit] = '{ this.local } // error + def macro5(using Quotes): Expr[Unit] = '{ this.inherited } // error + def macro6(using Quotes): Expr[Unit] = '{ localArg(this) } // error // error diff --git a/tests/pos/i22592.scala b/tests/pos/i22592.scala new file mode 100644 index 000000000000..f6a1f2eff696 --- /dev/null +++ b/tests/pos/i22592.scala @@ -0,0 +1,15 @@ +import scala.quoted.* + +trait Foo: + def inherited = () + +object Bar extends Foo: + def local = () + def localArg(arg: Any) = () + + def macro1(using Quotes): Expr[Unit] = '{ local } + def macro2(using Quotes): Expr[Unit] = '{ Bar.inherited } + def macro3(using Quotes): Expr[Unit] = '{ inherited } + def macro4(using Quotes): Expr[Unit] = '{ this.local } + def macro5(using Quotes): Expr[Unit] = '{ this.inherited } + def macro6(using Quotes): Expr[Unit] = '{ localArg(this) } From 91923ea2f78074cc46c82ba625e92c1625a431bc Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Tue, 22 Apr 2025 15:49:36 +0200 Subject: [PATCH 100/505] chore: Remove one test that only works with new experimental feature --- tests/neg/22145b.check | 36 ------------------------------------ tests/neg/22145b.scala | 40 ---------------------------------------- 2 files changed, 76 deletions(-) delete mode 100644 tests/neg/22145b.check delete mode 100644 tests/neg/22145b.scala diff --git a/tests/neg/22145b.check b/tests/neg/22145b.check deleted file mode 100644 index de605ce24276..000000000000 --- a/tests/neg/22145b.check +++ /dev/null @@ -1,36 +0,0 @@ --- [E008] Not Found Error: tests/neg/22145b.scala:15:19 ---------------------------------------------------------------- -15 | require(base.isWithin(p, start, end), "position is out of bounds") // error - | ^^^^^^^^^^^^^ - | value isWithin is not a member of Collection.this.Self --- [E008] Not Found Error: tests/neg/22145b.scala:28:59 ---------------------------------------------------------------- -28 | def positionAfter(p: Position): Position = self.base.positionAfter(p) // error - | ^^^^^^^^^^^^^^^^^^^^^^^ - |value positionAfter is not a member of Collection.this.Self. - |An extension method was tried, but could not be fully constructed: - | - | this.positionAfter(self.base) - | - | failed with: - | - | Found: (self.base : Collection.this.Self) - | Required: foo.Collection.given_is_Slice_Collection.Self² - | - | where: Self is a type in trait Collection - | Self² is a type in object given_is_Slice_Collection which is an alias of Collection.this.Slice - | --- [E008] Not Found Error: tests/neg/22145b.scala:29:50 ---------------------------------------------------------------- -29 | def apply(p: Position): Element = self.base.apply(p) // error - | ^^^^^^^^^^^^^^^ - |value apply is not a member of Collection.this.Self. - |An extension method was tried, but could not be fully constructed: - | - | this.apply(self.base) - | - | failed with: - | - | Found: (self.base : Collection.this.Self) - | Required: foo.Collection.given_is_Slice_Collection.Self² - | - | where: Self is a type in trait Collection - | Self² is a type in object given_is_Slice_Collection which is an alias of Collection.this.Slice - | diff --git a/tests/neg/22145b.scala b/tests/neg/22145b.scala deleted file mode 100644 index 5b8de5672fba..000000000000 --- a/tests/neg/22145b.scala +++ /dev/null @@ -1,40 +0,0 @@ -package foo - -import language.experimental.modularity - -trait Collection: - me => - - type Self - type Position - type Element - - final class Slice(private[Collection] val base: Self, val start: Position, val end: Position): - - final def apply(p: Position): Element = - require(base.isWithin(p, start, end), "position is out of bounds") // error - base.apply(p) - - end Slice - - given Slice is Collection: - - type Position = me.Position - type Element = me.Element - - extension (self: Self) - def start: Position = self.start - def end: Position = self.end - def positionAfter(p: Position): Position = self.base.positionAfter(p) // error - def apply(p: Position): Element = self.base.apply(p) // error - - end given - - extension (self: Self) - - def start: Position - def end: Position - def positionAfter(p: Position): Position - def apply(p: Position): Element - - end extension From ca1fb936399e920ee41079c0713184273c45910c Mon Sep 17 00:00:00 2001 From: som-snytt Date: Thu, 20 Feb 2025 08:34:49 -0800 Subject: [PATCH 101/505] Discourage default arg for extension receiver (#22492) Fixes #12460 I shied away from making it an error, as that is a language change that violates the rule that extension methods are ordinary methods. There are other restrictions, but an extension always allows explicit invocation `m()(x)` that could leverage a default. The caret is wrong on the second test case (~todo~). Edit: span of default getter was union of first parameter and the param RHS, so that the synthetic position of the getter symbol was a point at the first parameter. Now the getter tree gets the span of the RHS. (That span is non-synthetic, but the definition is still synthetic. The name pos of a synthetic is the point.) --- .../src/dotty/tools/dotc/ast/Desugar.scala | 1 + .../tools/dotc/reporting/ErrorMessageID.scala | 2 ++ .../dotty/tools/dotc/reporting/messages.scala | 11 ++++++++ .../dotty/tools/dotc/typer/RefChecks.scala | 25 ++++++++++++------- tests/warn/i12460.check | 24 ++++++++++++++++++ tests/warn/i12460.scala | 9 +++++++ 6 files changed, 63 insertions(+), 9 deletions(-) create mode 100644 tests/warn/i12460.check create mode 100644 tests/warn/i12460.scala diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index ca180e5ea612..0666cea91f20 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -338,6 +338,7 @@ object desugar { .withMods(Modifiers( meth.mods.flags & (AccessFlags | Synthetic) | (vparam.mods.flags & Inline), meth.mods.privateWithin)) + .withSpan(vparam.rhs.span) val rest = defaultGetters(vparams :: paramss1, n + 1) if vparam.rhs.isEmpty then rest else defaultGetter :: rest case _ :: paramss1 => // skip empty parameter lists and type parameters diff --git a/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala index c3cad8cbfea5..93744197cadd 100644 --- a/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala +++ b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala @@ -220,6 +220,8 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe case DeprecatedInfixNamedArgumentSyntaxID // errorNumber: 204 case GivenSearchPriorityID // errorNumber: 205 case EnumMayNotBeValueClassesID // errorNumber: 206 + case IllegalUnrollPlacementID // errorNumber: 207 - unused in LTS + case ExtensionHasDefaultID // errorNumber: 208 def errorNumber = ordinal - 1 diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index 886ed3979ba5..7cafa04f8792 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -2474,6 +2474,17 @@ class ExtensionNullifiedByMember(method: Symbol, target: Symbol)(using Context) | |The extension may be invoked as though selected from an arbitrary type if conversions are in play.""" +class ExtensionHasDefault(method: Symbol)(using Context) + extends Message(ExtensionHasDefaultID): + def kind = MessageKind.PotentialIssue + def msg(using Context) = + i"""Extension method ${hl(method.name.toString)} should not have a default argument for its receiver.""" + def explain(using Context) = + i"""The receiver cannot be omitted when an extension method is invoked as a selection. + |A default argument for that parameter would never be used in that case. + |An extension method can be invoked as a regular method, but if that is the intended usage, + |it should not be defined as an extension.""" + class TraitCompanionWithMutableStatic()(using Context) extends SyntaxMsg(TraitCompanionWithMutableStaticID) { def msg(using Context) = i"Companion of traits cannot define mutable @static fields" diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index bb58bb05fadf..128a0253a8cf 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -1062,22 +1062,21 @@ object RefChecks { * that are either both opaque types or both not. */ def checkExtensionMethods(sym: Symbol)(using Context): Unit = - if sym.is(Extension) && !sym.nextOverriddenSymbol.exists then + if sym.is(Extension) then extension (tp: Type) - def strippedResultType = Applications.stripImplicit(tp.stripPoly, wildcardOnly = true).resultType - def firstExplicitParamTypes = Applications.stripImplicit(tp.stripPoly, wildcardOnly = true).firstParamTypes + def explicit = Applications.stripImplicit(tp.stripPoly, wildcardOnly = true) def hasImplicitParams = tp.stripPoly match { case mt: MethodType => mt.isImplicitMethod case _ => false } - val target = sym.info.firstExplicitParamTypes.head // required for extension method, the putative receiver - val methTp = sym.info.strippedResultType // skip leading implicits and the "receiver" parameter + val explicitInfo = sym.info.explicit // consider explicit value params + val target = explicitInfo.firstParamTypes.head // required for extension method, the putative receiver + val methTp = explicitInfo.resultType // skip leading implicits and the "receiver" parameter def hidden = target.nonPrivateMember(sym.name) - .filterWithPredicate: - member => + .filterWithPredicate: member => member.symbol.isPublic && { val memberIsImplicit = member.info.hasImplicitParams val paramTps = if memberIsImplicit then methTp.stripPoly.firstParamTypes - else methTp.firstExplicitParamTypes + else methTp.explicit.firstParamTypes paramTps.isEmpty || memberIsImplicit && !methTp.hasImplicitParams || { val memberParamTps = member.info.stripPoly.firstParamTypes @@ -1089,7 +1088,15 @@ object RefChecks { } } .exists - if !target.typeSymbol.isOpaqueAlias && hidden + if sym.is(HasDefaultParams) then + val getterDenot = + val receiverName = explicitInfo.firstParamNames.head + val num = sym.info.paramNamess.flatten.indexWhere(_ == receiverName) + val getterName = DefaultGetterName(sym.name.toTermName, num = num) + sym.owner.info.member(getterName) + if getterDenot.exists + then report.warning(ExtensionHasDefault(sym), getterDenot.symbol.srcPos) + if !target.typeSymbol.isOpaqueAlias && !sym.nextOverriddenSymbol.exists && hidden then report.warning(ExtensionNullifiedByMember(sym, target.typeSymbol), sym.srcPos) end checkExtensionMethods diff --git a/tests/warn/i12460.check b/tests/warn/i12460.check new file mode 100644 index 000000000000..ba44bed1a18f --- /dev/null +++ b/tests/warn/i12460.check @@ -0,0 +1,24 @@ +-- [E208] Potential Issue Warning: tests/warn/i12460.scala:3:23 -------------------------------------------------------- +3 |extension (s: String = "hello, world") def invert = s.reverse.toUpperCase // warn + | ^ + | Extension method invert should not have a default argument for its receiver. + |--------------------------------------------------------------------------------------------------------------------- + | Explanation (enabled by `-explain`) + |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + | The receiver cannot be omitted when an extension method is invoked as a selection. + | A default argument for that parameter would never be used in that case. + | An extension method can be invoked as a regular method, but if that is the intended usage, + | it should not be defined as an extension. + --------------------------------------------------------------------------------------------------------------------- +-- [E208] Potential Issue Warning: tests/warn/i12460.scala:5:37 -------------------------------------------------------- +5 |extension (using String)(s: String = "hello, world") def revert = s.reverse.toUpperCase // warn + | ^ + | Extension method revert should not have a default argument for its receiver. + |--------------------------------------------------------------------------------------------------------------------- + | Explanation (enabled by `-explain`) + |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + | The receiver cannot be omitted when an extension method is invoked as a selection. + | A default argument for that parameter would never be used in that case. + | An extension method can be invoked as a regular method, but if that is the intended usage, + | it should not be defined as an extension. + --------------------------------------------------------------------------------------------------------------------- diff --git a/tests/warn/i12460.scala b/tests/warn/i12460.scala new file mode 100644 index 000000000000..0e37c6aa7de7 --- /dev/null +++ b/tests/warn/i12460.scala @@ -0,0 +1,9 @@ +//> using options -explain -Ystop-after:refchecks + +extension (s: String = "hello, world") def invert = s.reverse.toUpperCase // warn + +extension (using String)(s: String = "hello, world") def revert = s.reverse.toUpperCase // warn + +extension (s: String) + def divert(m: String = "hello, world") = (s+m).reverse.toUpperCase // ok + def divertimento(using String)(m: String = "hello, world") = (s+m).reverse.toUpperCase // ok From 6ec57128adb4f5bbb390c0749c3ac3a0465e562b Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Tue, 22 Apr 2025 19:26:18 +0200 Subject: [PATCH 102/505] Discourage default arg for extension receiver (#22492) Fixes #12460 I shied away from making it an error, as that is a language change that violates the rule that extension methods are ordinary methods. There are other restrictions, but an extension always allows explicit invocation `m()(x)` that could leverage a default. The caret is wrong on the second test case (~todo~). Edit: span of default getter was union of first parameter and the param RHS, so that the synthetic position of the getter symbol was a point at the first parameter. Now the getter tree gets the span of the RHS. (That span is non-synthetic, but the definition is still synthetic. The name pos of a synthetic is the point.) [Cherry-picked afb4806afe422eeedd060fba11509ac3c1f749f3][modified] From 4fd0e18e6441e6c94095e936c4a9456bb18464cd Mon Sep 17 00:00:00 2001 From: Joel Wilsson Date: Thu, 29 Aug 2024 18:31:17 +0200 Subject: [PATCH 103/505] Print parens for single method argument only if a direct tuple type A type alias of a tuple type should be printed without parenthesis. --- .../dotty/tools/dotc/core/Definitions.scala | 28 ++++++++---- .../tools/dotc/printing/RefinedPrinter.scala | 2 +- .../pc/tests/completion/CompletionSuite.scala | 44 +++++++++++++++++++ 3 files changed, 65 insertions(+), 9 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 26ddc47c6b89..f084e98e8806 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -1722,18 +1722,30 @@ class Definitions { def isPolymorphicAfterErasure(sym: Symbol): Boolean = (sym eq Any_isInstanceOf) || (sym eq Any_asInstanceOf) || (sym eq Object_synchronized) - /** Is this type a `TupleN` type? + def isTypeTestOrCast(sym: Symbol): Boolean = + (sym eq Any_isInstanceOf) + || (sym eq Any_asInstanceOf) + || (sym eq Any_typeTest) + || (sym eq Any_typeCast) + + /** Is `tp` a `TupleN` type? + * + * @return true if the type of `tp` is `TupleN[T1, T2, ..., Tn]` + */ + def isDirectTupleNType(tp: Type)(using Context): Boolean = + val arity = tp.argInfos.length + arity <= MaxTupleArity && { + val tupletp = TupleType(arity) + tupletp != null && tp.isRef(tupletp.symbol) + } + + /** Is `tp` (an alias of) a `TupleN` type? * * @return true if the dealiased type of `tp` is `TupleN[T1, T2, ..., Tn]` */ - def isTupleNType(tp: Type)(using Context): Boolean = { + def isTupleNType(tp: Type)(using Context): Boolean = val tp1 = tp.dealias - val arity = tp1.argInfos.length - arity <= MaxTupleArity && { - val tupletp = TupleType(arity) - tupletp != null && tp1.isRef(tupletp.symbol) - } - } + isDirectTupleNType(tp1) def tupleType(elems: List[Type]): Type = { val arity = elems.length diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 4fdfd7cb3e60..286d68319c4e 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -159,7 +159,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { changePrec(GlobalPrec) { val argStr: Text = if args.length == 2 - && !defn.isTupleNType(args.head) + && !defn.isDirectTupleNType(args.head) && !isGiven then atPrec(InfixPrec) { argText(args.head) } diff --git a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala index 27aa3f505b80..862257d7d1eb 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala @@ -146,6 +146,50 @@ class CompletionSuite extends BaseCompletionSuite: "XtensionMethod(a: Int): XtensionMethod" ) + @Test def tupleDirect = + check( + """ + |trait Foo { + | def setup: List[(String, String)] + |} + |object Foo { + | val foo: Foo = ??? + | foo.setup.exist@@ + |}""".stripMargin, + """|exists(p: ((String, String)) => Boolean): Boolean + |""".stripMargin + ) + + @Test def tupleAlias = + check( + """ + |trait Foo { + | def setup: List[Foo.TupleAliasResult] + |} + |object Foo { + | type TupleAliasResult = (String, String) + | val foo: Foo = ??? + | foo.setup.exist@@ + |}""".stripMargin, + """|exists(p: TupleAliasResult => Boolean): Boolean + |""".stripMargin + ) + + @Test def listAlias = + check( + """ + |trait Foo { + | def setup: List[Foo.ListAliasResult] + |} + |object Foo { + | type ListAliasResult = List[String] + | val foo: Foo = ??? + | foo.setup.exist@@ + |}""".stripMargin, + """|exists(p: ListAliasResult => Boolean): Boolean + |""".stripMargin + ) + @Ignore("This test should be handled by compiler fuzzy search") @Test def fuzzy = check( From 665c1f847c8a043e19b7d7c78efb45a7b10321d0 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Tue, 22 Apr 2025 19:28:38 +0200 Subject: [PATCH 104/505] Print parens for single method argument only if a direct tuple type A type alias of a tuple type should be printed without parenthesis. [Cherry-picked 57e2ef022d53d5725b9becc44b6ce9d6dcd4a353][modified] From 9bff6739bc922d1e0fd6e980454eee2bc0477ace Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Mon, 23 Sep 2024 20:47:44 +0200 Subject: [PATCH 105/505] Remove locale dependent FileSystemException check Fin SourceFile, files that do not exist are expected and related exceptions should be ignored. There are two relevant cases: scala> java.nio.file.Files.newInputStream(java.nio.file.FileSystems.getDefault().getPath("does-not-exist")) java.nio.file.NoSuchFileException: does-not-exist scala> java.nio.file.Files.newInputStream(java.nio.file.FileSystems.getDefault().getPath("regular-file-instead-of-directory/filename")) java.nio.file.FileSystemException: regular-file-instead-of-directory/filename: Not a directory Ideally, other I/O errors would be propagated to the caller. However, there is no reliable way to distinguish them based on the exceptions alone. In particular, the message cannot be checked, because it depends on the operating system and it is localized. Revert the addition of the check and just accept this. [Cherry-picked aa91e9fd26d262335a98fa8d1468801b97033703] --- compiler/src/dotty/tools/dotc/util/SourceFile.scala | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/util/SourceFile.scala b/compiler/src/dotty/tools/dotc/util/SourceFile.scala index 939690bb2ee0..7cad81b4096d 100644 --- a/compiler/src/dotty/tools/dotc/util/SourceFile.scala +++ b/compiler/src/dotty/tools/dotc/util/SourceFile.scala @@ -275,12 +275,11 @@ object SourceFile { def apply(file: AbstractFile | Null, codec: Codec): SourceFile = // Files.exists is slow on Java 8 (https://rules.sonarsource.com/java/tag/performance/RSPEC-3725), - // so cope with failure; also deal with path prefix "Not a directory". + // so cope with failure. val chars = try new String(file.toByteArray, codec.charSet).toCharArray catch - case _: NoSuchFileException => Array.empty[Char] - case fse: FileSystemException if fse.getMessage.endsWith("Not a directory") => Array.empty[Char] + case _: FileSystemException => Array.empty[Char] if isScript(file, chars) then ScriptSourceFile(file, chars) From 32cb51403531e0848b7364fcc1cd14f4d759b262 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Thu, 17 Oct 2024 15:55:34 -0700 Subject: [PATCH 106/505] Revert dubious retry in vulpix [Cherry-picked 72bff197cf8c9c97b7eb0eab1339109ca85b12bc] --- .../dotty/tools/vulpix/ParallelTesting.scala | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala index e15103046fbf..08ade9b035eb 100644 --- a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala +++ b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala @@ -12,7 +12,7 @@ import java.nio.file.{Files, NoSuchFileException, Path, Paths} import java.nio.charset.{Charset, StandardCharsets} import java.text.SimpleDateFormat import java.util.{HashMap, Timer, TimerTask} -import java.util.concurrent.{ExecutionException, TimeUnit, TimeoutException, Executors => JExecutors} +import java.util.concurrent.{TimeUnit, TimeoutException, Executors => JExecutors} import scala.collection.mutable import scala.io.{Codec, Source} @@ -511,12 +511,6 @@ trait ParallelTesting extends RunnerOrchestration { self => .and("-d", targetDir.getPath) .withClasspath(targetDir.getPath) - def waitForJudiciously(process: Process): Int = - try process.waitFor() - catch case _: InterruptedException => - try if process.waitFor(5L, TimeUnit.MINUTES) then process.exitValue() else -2 - finally Thread.currentThread.interrupt() - def compileWithJavac(fs: Array[String]) = if (fs.nonEmpty) { val fullArgs = Array( "-encoding", StandardCharsets.UTF_8.name, @@ -525,7 +519,7 @@ trait ParallelTesting extends RunnerOrchestration { self => val process = Runtime.getRuntime.exec("javac" +: fullArgs) val output = Source.fromInputStream(process.getErrorStream).mkString - if waitForJudiciously(process) != 0 then Some(output) + if process.waitFor() != 0 then Some(output) else None } else None @@ -704,11 +698,7 @@ trait ParallelTesting extends RunnerOrchestration { self => for fut <- eventualResults do try fut.get() - catch - case ee: ExecutionException if ee.getCause.isInstanceOf[InterruptedException] => - System.err.println("Interrupted (probably running after shutdown)") - ee.printStackTrace() - case ex: Exception => + catch case ex: Exception => System.err.println(ex.getMessage) ex.printStackTrace() From 0b9f7952068306c18a5f8dc4c7887e8d10743236 Mon Sep 17 00:00:00 2001 From: Jan Chyb Date: Tue, 26 Nov 2024 17:21:14 +0100 Subject: [PATCH 107/505] Add a check for correct Array shape in quotes.reflect.ClassOfConstant [Cherry-picked 80ae4086a10b4c593f7abb36c800ad8ca6cbfc8b] --- .../scala/quoted/runtime/impl/QuotesImpl.scala | 12 +++++++++++- tests/neg-macros/i21916.check | 15 +++++++++++++++ tests/neg-macros/i21916/Macro_1.scala | 9 +++++++++ tests/neg-macros/i21916/Test_2.scala | 3 +++ 4 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tests/neg-macros/i21916.check create mode 100644 tests/neg-macros/i21916/Macro_1.scala create mode 100644 tests/neg-macros/i21916/Test_2.scala diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index d4f2bdd0991b..f5a201de1f2e 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -2448,7 +2448,17 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler object ClassOfConstant extends ClassOfConstantModule: def apply(x: TypeRepr): ClassOfConstant = - // TODO check that the type is a valid class when creating this constant or let Ycheck do it? + // We only check if the supplied TypeRepr is valid if it contains an Array, + // as so far only that Array could cause issues + def correctTypeApplicationForArray(typeRepr: TypeRepr): Boolean = + val isArray = typeRepr.typeSymbol != dotc.core.Symbols.defn.ArrayClass + typeRepr match + case AppliedType(_, targs) if !targs.isEmpty => true + case _ => isArray + xCheckMacroAssert( + correctTypeApplicationForArray(x), + "Illegal empty Array type constructor. Please supply a type parameter." + ) dotc.core.Constants.Constant(x) def unapply(constant: ClassOfConstant): Some[TypeRepr] = Some(constant.typeValue) end ClassOfConstant diff --git a/tests/neg-macros/i21916.check b/tests/neg-macros/i21916.check new file mode 100644 index 000000000000..58a8ac43782a --- /dev/null +++ b/tests/neg-macros/i21916.check @@ -0,0 +1,15 @@ + +-- Error: tests/neg-macros/i21916/Test_2.scala:3:27 -------------------------------------------------------------------- +3 |@main def Test = Macro.test() // error + | ^^^^^^^^^^^^ + | Exception occurred while executing macro expansion. + | java.lang.AssertionError: Illegal empty Array type constructor. Please supply a type parameter. + | at Macro$.testImpl(Macro_1.scala:8) + | + |--------------------------------------------------------------------------------------------------------------------- + |Inline stack trace + |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + |This location contains code that was inlined from Macro_1.scala:3 +3 | inline def test() = ${testImpl} + | ^^^^^^^^^^^ + --------------------------------------------------------------------------------------------------------------------- diff --git a/tests/neg-macros/i21916/Macro_1.scala b/tests/neg-macros/i21916/Macro_1.scala new file mode 100644 index 000000000000..78af2cde2963 --- /dev/null +++ b/tests/neg-macros/i21916/Macro_1.scala @@ -0,0 +1,9 @@ +import scala.quoted._ +object Macro: + inline def test() = ${testImpl} + def testImpl(using Quotes): Expr[Any] = { + import quotes.reflect._ + val tpe = TypeRepr.of[Array[Byte]] match + case AppliedType(tycons, _) => tycons + Literal(ClassOfConstant(tpe)).asExpr + } diff --git a/tests/neg-macros/i21916/Test_2.scala b/tests/neg-macros/i21916/Test_2.scala new file mode 100644 index 000000000000..103bced0c04e --- /dev/null +++ b/tests/neg-macros/i21916/Test_2.scala @@ -0,0 +1,3 @@ +// lack of type ascription is on purpose, +// as that was part of what would cause the crash before. +@main def Test = Macro.test() // error From 78ddbb9b67dfd5465ba92f6a36d353814e864187 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Thu, 20 Feb 2025 03:18:16 -0800 Subject: [PATCH 108/505] Constructor companion gets privateWithin --- .../src/dotty/tools/dotc/core/NamerOps.scala | 1 + tests/neg/i18545.check | 26 +++++++++++++++++++ tests/neg/i18545.scala | 20 ++++++++++++++ tests/neg/i22560b.scala | 2 ++ tests/neg/i22560c/client_2.scala | 11 ++++++++ tests/neg/i22560c/lib_1.scala | 16 ++++++++++++ tests/pos/i22560.scala | 10 +++++++ tests/pos/i22560b/client_2.scala | 17 ++++++++++++ tests/pos/i22560b/lib_1.scala | 19 ++++++++++++++ 9 files changed, 122 insertions(+) create mode 100644 tests/neg/i18545.check create mode 100644 tests/neg/i18545.scala create mode 100644 tests/neg/i22560c/client_2.scala create mode 100644 tests/neg/i22560c/lib_1.scala create mode 100644 tests/pos/i22560b/client_2.scala create mode 100644 tests/pos/i22560b/lib_1.scala diff --git a/compiler/src/dotty/tools/dotc/core/NamerOps.scala b/compiler/src/dotty/tools/dotc/core/NamerOps.scala index 7129527fb22a..2fffa1fed1e5 100644 --- a/compiler/src/dotty/tools/dotc/core/NamerOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NamerOps.scala @@ -141,6 +141,7 @@ object NamerOps: cls.owner, cls.name.toTermName, flags, flags, constructorCompanionCompleter(cls), + cls.privateWithin, coord = cls.coord, assocFile = cls.assocFile) companion.moduleClass.registerCompanion(cls) diff --git a/tests/neg/i18545.check b/tests/neg/i18545.check new file mode 100644 index 000000000000..1b336b0cc5ab --- /dev/null +++ b/tests/neg/i18545.check @@ -0,0 +1,26 @@ +-- [E173] Reference Error: tests/neg/i18545.scala:16:20 ---------------------------------------------------------------- +16 | def test: IOLocal.IOLocalImpl[Int] = // error + | ^^^^^^^^^^^^^^^^^^^ + |class IOLocalImpl cannot be accessed as a member of iolib.IOLocal.type from the top-level definitions in package tests. + | private[IOLocal] class IOLocalImpl can only be accessed from object IOLocal in package iolib. +-- [E173] Reference Error: tests/neg/i18545.scala:17:24 ---------------------------------------------------------------- +17 | IOLocal.IOLocalImpl.apply(42) // error + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + |method apply cannot be accessed as a member of iolib.IOLocal.IOLocalImpl.type from the top-level definitions in package tests. + | private[IOLocal] method apply can only be accessed from object IOLocal in package iolib. +-- [E050] Type Error: tests/neg/i18545.scala:18:22 --------------------------------------------------------------------- +18 | def test2 = IOLocal.IOLocalImpl(42) // error + | ^^^^^^^^^^^^^^^^^^^ + | object IOLocalImpl in object IOLocal does not take parameters + | + | longer explanation available when compiling with `-explain` +-- [E173] Reference Error: tests/neg/i18545.scala:19:22 ---------------------------------------------------------------- +19 | def test3 = IOLocal.AltIOLocalImpl.apply(42) // error + | ^^^^^^^^^^^^^^^^^^^^^^ + |object AltIOLocalImpl cannot be accessed as a member of iolib.IOLocal.type from the top-level definitions in package tests. + | private[IOLocal] object AltIOLocalImpl can only be accessed from object IOLocal in package iolib. +-- [E173] Reference Error: tests/neg/i18545.scala:20:22 ---------------------------------------------------------------- +20 | def test4 = IOLocal.AltIOLocalImpl(42) // error + | ^^^^^^^^^^^^^^^^^^^^^^ + |object AltIOLocalImpl cannot be accessed as a member of iolib.IOLocal.type from the top-level definitions in package tests. + | private[IOLocal] object AltIOLocalImpl can only be accessed from object IOLocal in package iolib. diff --git a/tests/neg/i18545.scala b/tests/neg/i18545.scala new file mode 100644 index 000000000000..86f18cd60771 --- /dev/null +++ b/tests/neg/i18545.scala @@ -0,0 +1,20 @@ +package iolib: + case class IO[A](value: A) + + sealed trait IOLocal[A] + + object IOLocal: + def apply[A](default: A): IO[IOLocal[A]] = IO(new IOLocalImpl(default)) + + private[IOLocal] final class IOLocalImpl[A](default: A) extends IOLocal[A] + object IOLocalImpl + + private[IOLocal] final class AltIOLocalImpl[A](default: A) extends IOLocal[A] + +package tests: + import iolib.IOLocal + def test: IOLocal.IOLocalImpl[Int] = // error + IOLocal.IOLocalImpl.apply(42) // error + def test2 = IOLocal.IOLocalImpl(42) // error + def test3 = IOLocal.AltIOLocalImpl.apply(42) // error + def test4 = IOLocal.AltIOLocalImpl(42) // error diff --git a/tests/neg/i22560b.scala b/tests/neg/i22560b.scala index bce079e0eeb2..58b41b6f8766 100644 --- a/tests/neg/i22560b.scala +++ b/tests/neg/i22560b.scala @@ -12,7 +12,9 @@ package p: private[p] class C(i: Int) // ctor proxy gets privateWithin of class private[p] class D(i: Int) object D + private class E(i: Int) package q: def f() = p.C(42) // error def g() = p.D(42) // error + def h() = p.E(42) // error diff --git a/tests/neg/i22560c/client_2.scala b/tests/neg/i22560c/client_2.scala new file mode 100644 index 000000000000..c04720cd207b --- /dev/null +++ b/tests/neg/i22560c/client_2.scala @@ -0,0 +1,11 @@ + +package i22560: + val alpha = C.D() // error + + class Test extends Enumeration: + val Hearts = Val(27) // error + val Diamonds = Val() // error + +package q: + def f() = p.C(42) // error + def g() = p.D(42) // error diff --git a/tests/neg/i22560c/lib_1.scala b/tests/neg/i22560c/lib_1.scala new file mode 100644 index 000000000000..2d9d24962b8d --- /dev/null +++ b/tests/neg/i22560c/lib_1.scala @@ -0,0 +1,16 @@ + +package i22560: + + object C: + protected class D + + class Enumeration: + protected class Val(i: Int): + def this() = this(42) + object Val + +package p: + private[p] class C(i: Int) // companion gets privateWithin of class + private[p] class D(i: Int) // ctor proxy gets privateWithin of class + object D + diff --git a/tests/pos/i22560.scala b/tests/pos/i22560.scala index 947923aba259..af4382ba5a15 100644 --- a/tests/pos/i22560.scala +++ b/tests/pos/i22560.scala @@ -20,3 +20,13 @@ package companioned: class Test extends Enumeration: val Hearts = Val(27) val Diamonds = Val() + +package p: + + package internal: + + protected[p] class P(i : Int) + private[p] class Q(i : Int) + + def f = internal.P(42) + def g = internal.Q(42) diff --git a/tests/pos/i22560b/client_2.scala b/tests/pos/i22560b/client_2.scala new file mode 100644 index 000000000000..bb57276c12c6 --- /dev/null +++ b/tests/pos/i22560b/client_2.scala @@ -0,0 +1,17 @@ + +package companionless: + + class Test extends Enumeration: + val Hearts = Val(27) + val Diamonds = Val() + + +package companioned: + + class Test extends Enumeration: + val Hearts = Val(27) + val Diamonds = Val() + +package p: + + def f = internal.P(42) diff --git a/tests/pos/i22560b/lib_1.scala b/tests/pos/i22560b/lib_1.scala new file mode 100644 index 000000000000..d247d63ec9cf --- /dev/null +++ b/tests/pos/i22560b/lib_1.scala @@ -0,0 +1,19 @@ + +package companionless: + + class Enumeration: + protected class Val(i: Int): + def this() = this(42) + +package companioned: + + class Enumeration: + protected class Val(i: Int): + def this() = this(42) + protected object Val + +package p: + + package internal: + + protected[p] class P(i : Int) From 7681fef8b5de01e66116ffc78b83bcbe4d6b91b6 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Tue, 22 Apr 2025 19:32:57 +0200 Subject: [PATCH 109/505] Constructor companion gets privateWithin [Cherry-picked eea481fff44599de0215469e521b244efbaae141][modified] From b265a7600318523e954e0bccfe1c63e8f5b18d6f Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Tue, 22 Apr 2025 19:33:42 +0200 Subject: [PATCH 110/505] chore: avoid double configuration in scala2-library projects [Cherry-picked 0d21a162c4bbb48aeaf56c6bd52b6961318715ec][modified] From 633f1da2a0d97e7bd39ad65af5e37ae985261e79 Mon Sep 17 00:00:00 2001 From: philwalk Date: Fri, 21 Feb 2025 11:23:47 -0700 Subject: [PATCH 111/505] replaced previous commits with a cp filter in Jar.scala [Cherry-picked f24b5d15eaa3badfeb4b712b3f2d6c234e409a85] --- compiler/src/dotty/tools/io/Jar.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/io/Jar.scala b/compiler/src/dotty/tools/io/Jar.scala index b4c2024bb487..4f70bafecae9 100644 --- a/compiler/src/dotty/tools/io/Jar.scala +++ b/compiler/src/dotty/tools/io/Jar.scala @@ -50,7 +50,7 @@ class Jar(file: File) { def mainClass: Option[String] = manifest.map(_(Name.MAIN_CLASS)) /** The manifest-defined classpath String if available. */ def classPathString: Option[String] = - for (m <- manifest ; cp <- m.attrs.get(Name.CLASS_PATH)) yield cp + for (m <- manifest ; cp <- m.attrs.get(Name.CLASS_PATH) if !cp.isBlank()) yield cp def classPathElements: List[String] = classPathString match { case Some(s) => s.split("\\s+").toList case _ => Nil From 13b6b8c36926bb4fc7b1e56fd9c9e377816f1fcd Mon Sep 17 00:00:00 2001 From: Hamza Remmal Date: Fri, 21 Feb 2025 20:39:02 +0100 Subject: [PATCH 112/505] chore: Apply suggestions from code review [Cherry-picked 01fc715ee486bb2257165804f6a9ebcad2d29ddd] --- compiler/src/dotty/tools/io/Jar.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/io/Jar.scala b/compiler/src/dotty/tools/io/Jar.scala index 4f70bafecae9..6076638bff45 100644 --- a/compiler/src/dotty/tools/io/Jar.scala +++ b/compiler/src/dotty/tools/io/Jar.scala @@ -50,7 +50,7 @@ class Jar(file: File) { def mainClass: Option[String] = manifest.map(_(Name.MAIN_CLASS)) /** The manifest-defined classpath String if available. */ def classPathString: Option[String] = - for (m <- manifest ; cp <- m.attrs.get(Name.CLASS_PATH) if !cp.isBlank()) yield cp + for (m <- manifest ; cp <- m.attrs.get(Name.CLASS_PATH) if !cp.trim().isEmpty()) yield cp def classPathElements: List[String] = classPathString match { case Some(s) => s.split("\\s+").toList case _ => Nil From 2df2319bff1861f53fe4abe4f91cd3299a11672e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Rochala?= <48657087+rochala@users.noreply.github.com> Date: Mon, 24 Feb 2025 13:23:13 +0100 Subject: [PATCH 113/505] Warn universal extensions on opaque types (#22502) Fixes #22232 Work also done by @hamzaremmal, @julian-a-avar-c and @nmcb Co-authored-by: Hamza Remmal [Cherry-picked 7d79c561d2f7cc0b831a072c0cd4f722a8246062] --- .../dotty/tools/dotc/typer/RefChecks.scala | 4 +-- tests/warn/i22232.check | 28 ++++++++++++++++ tests/warn/i22232.scala | 32 +++++++++++++++++++ 3 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 tests/warn/i22232.check create mode 100644 tests/warn/i22232.scala diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 128a0253a8cf..70daeb600708 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -1067,7 +1067,7 @@ object RefChecks { def explicit = Applications.stripImplicit(tp.stripPoly, wildcardOnly = true) def hasImplicitParams = tp.stripPoly match { case mt: MethodType => mt.isImplicitMethod case _ => false } val explicitInfo = sym.info.explicit // consider explicit value params - val target = explicitInfo.firstParamTypes.head // required for extension method, the putative receiver + val target = explicitInfo.firstParamTypes.head.typeSymbol.info // required for extension method, the putative receiver val methTp = explicitInfo.resultType // skip leading implicits and the "receiver" parameter def hidden = target.nonPrivateMember(sym.name) @@ -1096,7 +1096,7 @@ object RefChecks { sym.owner.info.member(getterName) if getterDenot.exists then report.warning(ExtensionHasDefault(sym), getterDenot.symbol.srcPos) - if !target.typeSymbol.isOpaqueAlias && !sym.nextOverriddenSymbol.exists && hidden + if !sym.nextOverriddenSymbol.exists && hidden then report.warning(ExtensionNullifiedByMember(sym, target.typeSymbol), sym.srcPos) end checkExtensionMethods diff --git a/tests/warn/i22232.check b/tests/warn/i22232.check new file mode 100644 index 000000000000..cf3d6d4e004e --- /dev/null +++ b/tests/warn/i22232.check @@ -0,0 +1,28 @@ +-- [E194] Potential Issue Warning: tests/warn/i22232.scala:3:23 -------------------------------------------------------- +3 | extension (c: C) def equals(that: Any): Boolean = false // warn + | ^ + | Extension method equals will never be selected from type C + | because C already has a member with the same name and compatible parameter types. + | + | longer explanation available when compiling with `-explain` +-- [E194] Potential Issue Warning: tests/warn/i22232.scala:9:25 -------------------------------------------------------- +9 | extension (d: D) def equals(that: Any): Boolean = false // warn + | ^ + | Extension method equals will never be selected from type C + | because C already has a member with the same name and compatible parameter types. + | + | longer explanation available when compiling with `-explain` +-- [E194] Potential Issue Warning: tests/warn/i22232.scala:13:38 ------------------------------------------------------- +13 | extension (arr: MyString[Byte]) def length: Int = 0 // warn + | ^ + | Extension method length will never be selected from type String + | because String already has a member with the same name and compatible parameter types. + | + | longer explanation available when compiling with `-explain` +-- [E194] Potential Issue Warning: tests/warn/i22232.scala:17:46 ------------------------------------------------------- +17 | extension [T <: MyString[Byte]](arr: T) def length: Int = 0 // warn + | ^ + | Extension method length will never be selected from type String + | because String already has a member with the same name and compatible parameter types. + | + | longer explanation available when compiling with `-explain` diff --git a/tests/warn/i22232.scala b/tests/warn/i22232.scala new file mode 100644 index 000000000000..79b8317a7329 --- /dev/null +++ b/tests/warn/i22232.scala @@ -0,0 +1,32 @@ +class C +object C: + extension (c: C) def equals(that: Any): Boolean = false // warn + +object X: + class C + opaque type D <: C = C + object D: + extension (d: D) def equals(that: Any): Boolean = false // warn + +object Upperbound1: + opaque type MyString[+T] <: String = String + extension (arr: MyString[Byte]) def length: Int = 0 // warn + +object Upperbound2: + opaque type MyString[+T] <: String = String + extension [T <: MyString[Byte]](arr: T) def length: Int = 0 // warn + +object Upperbound3: + opaque type MyString[+T] <: String = String + extension [T](arr: T) def length: Int = 0 // nowarn + +object NonUpperbound1: + opaque type MyString[+T] = String + extension (arr: MyString[Byte]) def length: Int = 0 // nowarn +object NonUpperbound2: + opaque type MyString[+T] = String + extension [T <: MyString[Byte]](arr: T) def length2: Int = 0 // nowarn + +object NonUpperbound3: + opaque type MyString[+T] = String + extension [T](arr: T) def length: Int = 0 // nowarn From dba8eaa3cdb5ed6136c8f6fa2c78f93ecb3c87bf Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Wed, 9 Oct 2024 01:54:09 +0200 Subject: [PATCH 114/505] Make overload pruning based on result types less aggressive `adaptByResult` was introduced in 2015 in 54835b6fb19ab0758c7503fb6f0e990ee4c25491 as a last step in overloading resolution: > Take expected result type into account more often for overloading resolution > > Previously, the expected result type of a FunProto type was ignored and taken into > account only in case of ambiguities. arrayclone-new.scala shows that this is not enough. > In a case like > > val x: Array[Byte] = Array(1, 2) > > we typed 1, 2 to be Int, so overloading resulution would give the Array.apply of > type (Int, Int*)Array[Int]. But that's a dead end, since Array[Int] is not a subtype > of Array[Byte]. > > This commit proposes the following modified rule for overloading resulution: > > A method alternative is applicable if ... (as before), and if its result type > is copmpatible with the expected type of the method application. > > The commit does not pre-select alternatives based on comparing with the expected > result type. I tried that but it slowed down typechecking by a factor of at least 4. > Instead, we proceed as usual, ignoring the result type except in case of > ambiguities, but check whether the result of overloading resolution has a > compatible result type. If that's not the case, we filter all alternatives > for result type compatibility and try again. In i21410.scala this means we end up checking: F[?U] <:< Int (where ?U is unconstrained, because the check is done without looking at the argument types) The problem is that the subtype check returning false does not mean that there is no instantiation of `?U` that would make this check return true, just that type inference was not able to come up with one. This could happen for any number of reason but commonly will happen with match types since inference cannot do much with them. We cannot avoid this by taking the argument types into account, because this logic was added precisely to handle cases where the argument types mislead you because adaptation isn't taken into account. Instead, we can approximate type variables in the result type to trade false negatives for false positives which should be less problematic here. Fixes #21410. [Cherry-picked 528d0f029ab17dfbc9bac80b3bb33d60220c467e] --- .../src/dotty/tools/dotc/typer/Applications.scala | 10 +++++++--- tests/pos/i21410.scala | 12 ++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 tests/pos/i21410.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 5254ec3712c1..8f29c673348d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -1949,16 +1949,20 @@ trait Applications extends Compatibility { def resolveOverloaded(alts: List[TermRef], pt: Type)(using Context): List[TermRef] = record("resolveOverloaded") - /** Is `alt` a method or polytype whose result type after the first value parameter + /** Is `alt` a method or polytype whose approximated result type after the first value parameter * section conforms to the expected type `resultType`? If `resultType` * is a `IgnoredProto`, pick the underlying type instead. + * + * Using approximated result types is necessary to avoid false negatives + * due to incomplete type inference such as in tests/pos/i21410.scala. */ def resultConforms(altSym: Symbol, altType: Type, resultType: Type)(using Context): Boolean = resultType.revealIgnored match { case resultType: ValueType => altType.widen match { - case tp: PolyType => resultConforms(altSym, instantiateWithTypeVars(tp), resultType) - case tp: MethodType => constrainResult(altSym, tp.resultType, resultType) + case tp: PolyType => resultConforms(altSym, tp.resultType, resultType) + case tp: MethodType => + constrainResult(altSym, wildApprox(tp.resultType), resultType) case _ => true } case _ => true diff --git a/tests/pos/i21410.scala b/tests/pos/i21410.scala new file mode 100644 index 000000000000..c3ba3ea862bc --- /dev/null +++ b/tests/pos/i21410.scala @@ -0,0 +1,12 @@ +class A +object Test: + type F[X] <: Any = X match + case A => Int + + def foo[T](x: String): T = ??? + def foo[U](x: U): F[U] = ??? + + val x1 = foo(A()) + val y: Int = x1 + + val x2: Int = foo(A()) // error From 73aaf2a9b122111306da79df62290c619c606127 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Thu, 10 Oct 2024 19:41:58 +0200 Subject: [PATCH 115/505] Make `Applications#resolveMapped` preserve annotations Overloading may create a temporary symbol via `Applications#resolveMapped`, but before this commit, this symbol did not carry the annotations from the original symbol. This meant in particular that `isInlineable` would always return false for them. This matters because during the course of overloading resolution we might call `ProtoTypes.Compatibility#constrainResult` which special-cases transparent inline methods. Fixes a regression in Monocle introduced in the previous commit. wip [Cherry-picked f7259cf77e053b00068bd5dca124e9a3013489dd] --- .../src/dotty/tools/dotc/typer/Applications.scala | 1 + tests/pos/i21410c.scala | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 tests/pos/i21410c.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 8f29c673348d..cf98e67f7169 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -2308,6 +2308,7 @@ trait Applications extends Compatibility { if t.exists && alt.symbol.exists then val (trimmed, skipped) = trimParamss(t.stripPoly, alt.symbol.rawParamss) val mappedSym = alt.symbol.asTerm.copy(info = t) + mappedSym.annotations = alt.symbol.annotations mappedSym.rawParamss = trimmed val (pre, totalSkipped) = mappedAltInfo(alt.symbol) match case Some((pre, prevSkipped)) => diff --git a/tests/pos/i21410c.scala b/tests/pos/i21410c.scala new file mode 100644 index 000000000000..21f69fec20fa --- /dev/null +++ b/tests/pos/i21410c.scala @@ -0,0 +1,11 @@ +class AppliedPIso[A, B]() +case class User(age: Int) + +object Test: + extension [From, To](from: From) + def focus(): AppliedPIso[From, From] = ??? + transparent inline def focus(inline lambda: (From => To)): Any = ??? + + + val u = User(1) + val ap: AppliedPIso[User, User] = u.focus(_.age) // error From 95b8702eeb326fce82852d61b26e3997c11a0f78 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Sat, 12 Oct 2024 10:41:03 +0200 Subject: [PATCH 116/505] Avoid even more false negatives in overload pruning The changes two commits ago were not enough to handle i21410b.scala because we end up checking: Tuple.Map[WildcardType(...), List] <: (List[Int], List[String]) which fails because a match type with a wildcard argument apparently only gets reduced when the match type case is not parameterized. To handle this more generally we use AvoidWildcardsMap to remove wildcards from the result type, but since we want to prevent false negatives we start with `variance = -1` to get a lower-bound instead of an upper-bound. [Cherry-picked 32ac2e62f9b18aecf0064236a7ce6c60a1bbf579] --- .../src/dotty/tools/dotc/typer/Applications.scala | 13 ++++++++++--- tests/pos/i21410b.scala | 10 ++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 tests/pos/i21410b.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index cf98e67f7169..8947a2941cc0 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -1953,8 +1953,8 @@ trait Applications extends Compatibility { * section conforms to the expected type `resultType`? If `resultType` * is a `IgnoredProto`, pick the underlying type instead. * - * Using approximated result types is necessary to avoid false negatives - * due to incomplete type inference such as in tests/pos/i21410.scala. + * Using an approximated result type is necessary to avoid false negatives + * due to incomplete type inference such as in tests/pos/i21410.scala and tests/pos/i21410b.scala. */ def resultConforms(altSym: Symbol, altType: Type, resultType: Type)(using Context): Boolean = resultType.revealIgnored match { @@ -1962,7 +1962,14 @@ trait Applications extends Compatibility { altType.widen match { case tp: PolyType => resultConforms(altSym, tp.resultType, resultType) case tp: MethodType => - constrainResult(altSym, wildApprox(tp.resultType), resultType) + val wildRes = wildApprox(tp.resultType) + + class ResultApprox extends AvoidWildcardsMap: + // Avoid false negatives by approximating to a lower bound + variance = -1 + + val approx = ResultApprox()(wildRes) + constrainResult(altSym, approx, resultType) case _ => true } case _ => true diff --git a/tests/pos/i21410b.scala b/tests/pos/i21410b.scala new file mode 100644 index 000000000000..a17ad59bc59e --- /dev/null +++ b/tests/pos/i21410b.scala @@ -0,0 +1,10 @@ +object Test: + def foo[T](x: Option[T]): T = ??? + def foo[T <: Tuple](x: T): Tuple.Map[T, List] = ??? + + val tup: (Int, String) = (1, "") + + val x = foo(tup) + val y: (List[Int], List[String]) = x + + val x2: (List[Int], List[String]) = foo(tup) // error From a1d6be08cc182b9ad53dd23c3ae954cd40a402ab Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Tue, 22 Apr 2025 20:11:52 +0200 Subject: [PATCH 117/505] backport: Also backport missing https://github.com/scala/scala3/pull/18893 --- compiler/src/dotty/tools/dotc/core/NamerOps.scala | 7 +++++-- tests/pos/i22560b/client_2.scala | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/NamerOps.scala b/compiler/src/dotty/tools/dotc/core/NamerOps.scala index 2fffa1fed1e5..82ebb03b9662 100644 --- a/compiler/src/dotty/tools/dotc/core/NamerOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NamerOps.scala @@ -113,8 +113,11 @@ object NamerOps: var flags = ApplyProxyFlags | (constr.flagsUNSAFE & AccessFlags) if cls.is(Protected) && !modcls.is(Protected) then flags |= Protected newSymbol( - modcls, nme.apply, flags, - ApplyProxyCompleter(constr), coord = constr.coord) + modcls, nme.apply, + flags, + ApplyProxyCompleter(constr), + cls.privateWithin, + constr.coord) for dcl <- cls.info.decls do if dcl.isConstructor then scope.enter(proxy(dcl)) scope diff --git a/tests/pos/i22560b/client_2.scala b/tests/pos/i22560b/client_2.scala index bb57276c12c6..5376bcfa03cd 100644 --- a/tests/pos/i22560b/client_2.scala +++ b/tests/pos/i22560b/client_2.scala @@ -14,4 +14,4 @@ package companioned: package p: - def f = internal.P(42) + def f = new internal.P(42) From 8a869d8a232f193442a10b2bc0d7202306534312 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Thu, 20 Feb 2025 15:18:19 -0800 Subject: [PATCH 118/505] Check only stable qual for import prefix [Cherry-picked 5429dfa83808e53040b4535d7d1c0d3c9543fe29] --- .../tools/dotc/transform/CheckUnused.scala | 2 +- tests/warn/i22629.scala | 42 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 tests/warn/i22629.scala diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index a454c59eea7b..f9bfbe680352 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -73,7 +73,7 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha val target = res.dealias.typeSymbol resolveUsage(target, target.name, res.importPrefix.skipPackageObject) // case _: T => case _ => - else if tree.qualifier.srcPos.isSynthetic || name.exists(_ != tree.symbol.name) then + else if tree.qualifier.srcPos.isSynthetic && tree.qualifier.tpe.isStable || name.exists(_ != tree.symbol.name) then if !ignoreTree(tree) then resolveUsage(tree.symbol, name, tree.qualifier.tpe) else diff --git a/tests/warn/i22629.scala b/tests/warn/i22629.scala new file mode 100644 index 000000000000..53d17ec4da3b --- /dev/null +++ b/tests/warn/i22629.scala @@ -0,0 +1,42 @@ +//> using options -Wunused:all -Yno-deep-subtypes "-Wconf:msg=set repeatedly:s" + +//import either.* + +trait ResultMapper[A] { + final def map[B](f: A => B): ResultMapper[B] = ??? + + infix final def and[B](other: ResultMapper[B]): ResultMapper[(A, B)] = ??? +} + +trait BoilerplateResultMappers { + + def and[B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W]( + b: ResultMapper[B], c: ResultMapper[C], d: ResultMapper[D], e: ResultMapper[E], f: ResultMapper[F], g: ResultMapper[G], h: ResultMapper[H], i: ResultMapper[I], j: ResultMapper[J], k: ResultMapper[K], l: ResultMapper[L], m: ResultMapper[M], n: ResultMapper[N], o: ResultMapper[O], p: ResultMapper[P], q: ResultMapper[Q], r: ResultMapper[R], s: ResultMapper[S], t: ResultMapper[T], u: ResultMapper[U], v: ResultMapper[V], w: ResultMapper[W] + ): ResultMapper[(B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W)] = + (b and c and d and e and f and g and h and i and j and k and l and m and n and o and p and q and r and s and t and u and v and w).map { + case ((((((((((((((((((((((b), c), d), e), f), g), h), i), j), k), l), m), n), o), p), q), r), s), t), u), v), w) => + (b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w) + } +} + +/* +object either { + type ResultMapperException = RuntimeException + implicit class EitherOps[A](private val ea: Either[ResultMapperException, A]) extends AnyVal { + def and[B](eb: Either[ResultMapperException, B]): Either[ResultMapperException, (A, B)] = + (ea, eb) match { + case (Right(a), Right(b)) => + Right((a, b)) + + case (Right(_), Left(ex)) => + Left(ex) + + case (Left(ex), Right(_)) => + Left(ex) + + case (Left(_), Left(_)) => + Left(RuntimeException()) + } + } +} +*/ From 5ab90ffe88fcfde405f85c7c1f61558a62a156b2 Mon Sep 17 00:00:00 2001 From: kasiaMarek Date: Tue, 25 Feb 2025 12:40:07 +0100 Subject: [PATCH 119/505] chore: check name when renaming [Cherry-picked ec610bd4771533bac44fd65301d984d15eb50d2e] --- .../dotty/tools/pc/PcRenameProvider.scala | 16 +++++++++--- .../tools/pc/tests/edit/PcRenameSuite.scala | 26 +++++++++++++++++++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/PcRenameProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/PcRenameProvider.scala index 666ccf9c614f..467f331ea7dc 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/PcRenameProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/PcRenameProvider.scala @@ -18,11 +18,19 @@ final class PcRenameProvider( name: Option[String] ) extends WithSymbolSearchCollector[l.TextEdit](driver, params): private val forbiddenMethods = - Set("equals", "hashCode", "unapply", "unary_!", "!") + Set("equals", "hashCode", "unapply", "apply", "", "unary_!", "!") + + private val soughtSymbolNames = soughtSymbols match + case Some((symbols, _)) => + symbols.filterNot(_.isError).map(symbol => symbol.decodedName.toString) + case None => Set.empty[String] + def canRenameSymbol(sym: Symbol)(using Context): Boolean = - (!sym.is(Method) || !forbiddenMethods(sym.decodedName)) - && (sym.ownersIterator.drop(1).exists(ow => ow.is(Method)) - || sym.source.path.isWorksheet) + val decodedName = sym.decodedName + def isForbiddenMethod = sym.is(Method) && forbiddenMethods(decodedName) + def local = sym.ownersIterator.drop(1).exists(ow => ow.is(Method)) + def isInWorksheet = sym.source.path.isWorksheet + !isForbiddenMethod && (local || isInWorksheet) && soughtSymbolNames(decodedName) def prepareRename(): Option[l.Range] = soughtSymbols.flatMap((symbols, pos) => diff --git a/presentation-compiler/test/dotty/tools/pc/tests/edit/PcRenameSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/edit/PcRenameSuite.scala index 23c81fcf515a..3226018f88d4 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/edit/PcRenameSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/edit/PcRenameSuite.scala @@ -508,3 +508,29 @@ class PcRenameSuite extends BasePcRenameSuite: | ??? | end bar""".stripMargin ) + + @Test def `apply-rename` = + check( + """|object B { + | def locally = { + | object A{ def app@@ly(a: Int) = ??? } + | A(123) + | A.apply(123) + | } + |} + |""".stripMargin, + wrap = false + ) + + @Test def `constructor-rename` = + check( + """|object B { + | def locally = { + | class A(a : String){ def th@@is(a: Int) = this(a.toString) } + | A(123) + | A.apply(123) + | } + |} + |""".stripMargin, + wrap = false + ) From 6375c9418196422665188ae56625407f75111724 Mon Sep 17 00:00:00 2001 From: kasiaMarek Date: Tue, 25 Feb 2025 12:49:20 +0100 Subject: [PATCH 120/505] test: add type params selection range test [Cherry-picked 666f393f9fe1e36e35774210b77cb270e4bc1831] --- .../tools/pc/tests/SelectionRangeSuite.scala | 28 +++++-------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/presentation-compiler/test/dotty/tools/pc/tests/SelectionRangeSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/SelectionRangeSuite.scala index e277a67c466b..143d998a0ec1 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/SelectionRangeSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/SelectionRangeSuite.scala @@ -123,27 +123,13 @@ class SelectionRangeSuite extends BaseSelectionRangeSuite: |}""".stripMargin ) ) + + @Test def `def - type params` = check( - """|object Main extends App { - | val func = (a@@: Int, b: Int) => - | a + b - |}""".stripMargin, - List[String]( - """|object Main extends App { - | val func = (>>region>>a: Int< - | a + b - |}""".stripMargin, - """|object Main extends App { - | val func = (>>region>>a: Int, b: Int< - | a + b - |}""".stripMargin, - """|object Main extends App { - | val func = >>region>>(a: Int, b: Int) => - | a + b<>region>>val func = (a: Int, b: Int) => - | a + b<>region>>Type <: T1<>region>>Type <: T1, B<>region>>def foo[Type <: T1, B](hi: Int, b: Int, c:Int) = ???< Date: Thu, 27 Feb 2025 12:33:18 +0100 Subject: [PATCH 121/505] fix: don't search for members in pc info when irrelevant [Cherry-picked 53b2786ab9351d852e0352629bcc698c44ead15b] --- .../tools/pc/SymbolInformationProvider.scala | 8 +++- .../dotty/tools/pc/tests/info/InfoSuite.scala | 47 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/SymbolInformationProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/SymbolInformationProvider.scala index ccda618078b8..8bed605a87f8 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/SymbolInformationProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/SymbolInformationProvider.scala @@ -55,7 +55,13 @@ class SymbolInformationProvider(using Context): val classOwner = sym.ownersIterator.drop(1).find(s => s.isClass || s.is(Flags.Module)) val overridden = sym.denot.allOverriddenSymbols.toList - val memberDefAnnots = sym.info.membersBasedOnFlags(Flags.Method, Flags.EmptyFlags).flatMap(_.allSymbols).flatMap(_.denot.annotations) + val memberDefAnnots = + if classSym.exists then + classSym.info + .membersBasedOnFlags(Flags.Method, Flags.EmptyFlags) + .flatMap(_.allSymbols) + .flatMap(_.denot.annotations) + else Nil val pcSymbolInformation = PcSymbolInformation( diff --git a/presentation-compiler/test/dotty/tools/pc/tests/info/InfoSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/info/InfoSuite.scala index 8464c4d69da4..57ceb7a099d7 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/info/InfoSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/info/InfoSuite.scala @@ -8,6 +8,9 @@ import scala.meta.pc.PcSymbolInformation import dotty.tools.pc.base.BasePCSuite import scala.language.unsafeNulls import org.junit.Test +import scala.meta.internal.metals.CompilerOffsetParams +import java.nio.file.Paths +import scala.annotation.nowarn class InfoSuite extends BasePCSuite { @@ -53,4 +56,48 @@ class InfoSuite extends BasePCSuite { |scala/collection/IterableOnceOps#flatMap(). |""".stripMargin ) + + @Test def i7251 = + withSource( + """|package a + |sealed trait TA: + | type SomeType + |trait TB extends TA: + | type SomeType = Int + |""".stripMargin + ) + val info = presentationCompiler.info("a/TA#SomeType#").get() + assertNoDiff(info.get().symbol(), "a/TA#SomeType#") + + @Test def memberDefsAnnotations = + def assertMemberDefsAnnotations(symbol: String, expected: String) = + val info = presentationCompiler.info(symbol).get() + assertNoDiff(info.get().memberDefsAnnotations().asScala.mkString("\n"), expected, Some(symbol)) + withSource( + """|package a + |import scala.annotation.nowarn + |sealed trait TA: + | @nowarn + | def aaa = 1 + | + |object O: + | @nowarn + | def aaa = 1 + | + |class D: + | @nowarn + | def bbb = 1 + |""".stripMargin + ) + assertMemberDefsAnnotations("a/TA#", "scala.annotation.nowarn") + assertMemberDefsAnnotations("a/O.", "scala.annotation.nowarn") + assertMemberDefsAnnotations("a/D#", "scala.annotation.nowarn") + assertMemberDefsAnnotations("a/D#bbb().", "") + + // hacky way to add a source file to the presentation compiler sources + private def withSource(code: String) = + val filename = "Hover.scala" + val pcParams = CompilerOffsetParams(Paths.get(filename).toUri(), code, 0) + presentationCompiler.hover(pcParams).get() + } From 3098364db802a5c39933e704caa4e52525ff634e Mon Sep 17 00:00:00 2001 From: Seth Tisue Date: Thu, 27 Feb 2025 17:44:30 -0800 Subject: [PATCH 122/505] sbt 1.10.7 (was 1.10.5) [Cherry-picked fe0ec858a9d5b2aa67574d08c55b783a8c773180] --- .github/Dockerfile | 2 +- community-build/src/scala/dotty/communitybuild/projects.scala | 2 +- project/Dependencies.scala | 2 +- project/build.properties | 2 +- .../sourcepath-with-inline-api-hash/project/build.properties | 2 +- .../sourcepath-with-inline/project/build.properties | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/Dockerfile b/.github/Dockerfile index 3ba5466c30b8..e9b449421858 100644 --- a/.github/Dockerfile +++ b/.github/Dockerfile @@ -22,5 +22,5 @@ RUN apt-get update && \ # Install sbt ENV SBT_HOME /usr/local/sbt ENV PATH ${SBT_HOME}/bin:${PATH} -ENV SBT_VERSION 1.10.5 +ENV SBT_VERSION 1.10.7 RUN curl -sL "https://github.com/sbt/sbt/releases/download/v$SBT_VERSION/sbt-$SBT_VERSION.tgz" | gunzip | tar -x -C /usr/local \ No newline at end of file diff --git a/community-build/src/scala/dotty/communitybuild/projects.scala b/community-build/src/scala/dotty/communitybuild/projects.scala index c8e16d7df946..d8d791682cd3 100644 --- a/community-build/src/scala/dotty/communitybuild/projects.scala +++ b/community-build/src/scala/dotty/communitybuild/projects.scala @@ -128,7 +128,7 @@ final case class SbtCommunityProject( case Some(ivyHome) => List(s"-Dsbt.ivy.home=$ivyHome") case _ => Nil extraSbtArgs ++ sbtProps ++ List( - "-sbt-version", "1.10.5", + "-sbt-version", "1.10.7", "-Dsbt.supershell=false", s"-Ddotty.communitybuild.dir=$communitybuildDir", s"--addPluginSbtFile=$sbtPluginFilePath" diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 427b53e45221..22871db0570a 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -28,5 +28,5 @@ object Dependencies { "com.vladsch.flexmark" % "flexmark-ext-yaml-front-matter" % flexmarkVersion, ) - val compilerInterface = "org.scala-sbt" % "compiler-interface" % "1.10.4" + val compilerInterface = "org.scala-sbt" % "compiler-interface" % "1.10.7" } diff --git a/project/build.properties b/project/build.properties index db1723b08622..73df629ac1a7 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.10.5 +sbt.version=1.10.7 diff --git a/tests/cmdTest-sbt-tests/sourcepath-with-inline-api-hash/project/build.properties b/tests/cmdTest-sbt-tests/sourcepath-with-inline-api-hash/project/build.properties index db1723b08622..73df629ac1a7 100644 --- a/tests/cmdTest-sbt-tests/sourcepath-with-inline-api-hash/project/build.properties +++ b/tests/cmdTest-sbt-tests/sourcepath-with-inline-api-hash/project/build.properties @@ -1 +1 @@ -sbt.version=1.10.5 +sbt.version=1.10.7 diff --git a/tests/cmdTest-sbt-tests/sourcepath-with-inline/project/build.properties b/tests/cmdTest-sbt-tests/sourcepath-with-inline/project/build.properties index db1723b08622..73df629ac1a7 100644 --- a/tests/cmdTest-sbt-tests/sourcepath-with-inline/project/build.properties +++ b/tests/cmdTest-sbt-tests/sourcepath-with-inline/project/build.properties @@ -1 +1 @@ -sbt.version=1.10.5 +sbt.version=1.10.7 From ca77d84a8bb47fd6fd78151f734bd2d3874cd8a6 Mon Sep 17 00:00:00 2001 From: som-snytt Date: Fri, 28 Feb 2025 03:47:32 -0800 Subject: [PATCH 123/505] Regression test for extension nullification, nowarn for different opacities (#21191) Fixes #21190 ~Adjust~ test that params must not be of different opacity ~opaque~. ~Other aliases are permitted, but could check if they are effectively final. String alias can't be overridden.~ The tweak was https://github.com/scala/scala3/pull/22268 and the ticket was a duplicate. In the meantime, it also doesn't warn for any override, so the previous concern about aliases doesn't apply. [Cherry-picked ee62b32974eec926dc813b1d2d649a9e970ffa16] --- tests/warn/i21190.scala | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tests/warn/i21190.scala diff --git a/tests/warn/i21190.scala b/tests/warn/i21190.scala new file mode 100644 index 000000000000..652a4ad36853 --- /dev/null +++ b/tests/warn/i21190.scala @@ -0,0 +1,23 @@ + +//> using options -Werror + +opaque type FromEnd = Int +object FromEnd: + inline def apply(i: Int): FromEnd = i + extension (fe: FromEnd) + inline def value: Int = fe + +// Warning appears when extension is in same namespace as opaque type +extension [A](a: Array[A]) + inline def apply(fe: FromEnd): A = + a(a.length - 1 - FromEnd.value(fe)) + +class R: + def run(): String = + val xs = Array(1, 2, 3) + + s"""First element = ${xs(0)} + |Last element = ${xs(FromEnd(0))}""".stripMargin + +@main def test = println: + R().run() From 05b01e775fdf7dda4d4e702054acb4ea441d22ce Mon Sep 17 00:00:00 2001 From: Vadim Chelyshov Date: Fri, 7 Jun 2024 15:21:50 +0300 Subject: [PATCH 124/505] completions: do not complete package There is an issue with completions for package in Metals. ```scala // code package one@@ // compeltions oneCURSOR ``` It seems there is no need in completions for Package at all. [Cherry-picked 7c76ded6b1e02a986d68ea8b3138a257afc5baba] --- .../dotty/tools/dotc/interactive/Completion.scala | 2 ++ .../pc/tests/completion/CompletionSuite.scala | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/compiler/src/dotty/tools/dotc/interactive/Completion.scala b/compiler/src/dotty/tools/dotc/interactive/Completion.scala index 61a1db44d8b0..ba37a48287ff 100644 --- a/compiler/src/dotty/tools/dotc/interactive/Completion.scala +++ b/compiler/src/dotty/tools/dotc/interactive/Completion.scala @@ -88,6 +88,8 @@ object Completion: * Otherwise, provide no completion suggestion. */ def completionMode(path: List[untpd.Tree], pos: SourcePosition): Mode = path match + // Ignore `package foo@@` and `package foo.bar@@` + case ((_: tpd.Select) | (_: tpd.Ident)):: (_ : tpd.PackageDef) :: _ => Mode.None case GenericImportSelector(sel) => if sel.imported.span.contains(pos.span) then Mode.ImportOrExport // import scala.@@ else if sel.isGiven && sel.bound.span.contains(pos.span) then Mode.ImportOrExport diff --git a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala index 862257d7d1eb..bc9f158ca97c 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala @@ -2189,3 +2189,17 @@ class CompletionSuite extends BaseCompletionSuite: |""".stripMargin, topLines = Some(3) ) + + @Test def `packageIssueIdent` = + check( + """package one@@ + |""".stripMargin, + "" + ) + + @Test def `packageIssueSelect` = + check( + """package one.two@@ + |""".stripMargin, + "" + ) From 42e1ada837d2b0f75eff1b039f39d1d9083c3c27 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Mon, 24 Feb 2025 19:37:29 +0100 Subject: [PATCH 125/505] Add REPL flag to quit after evaluating init script --- bin/replQ | 6 + .../tools/dotc/config/ScalaSettings.scala | 1 + .../src/dotty/tools/repl/ReplDriver.scala | 4 +- .../tools/scripting/BashExitCodeTests.scala | 3 + .../dotty/tools/scripting/ScriptTestEnv.scala | 5 +- dist/bin/repl | 88 ++++++++++++++ dist/bin/repl.bat | 110 ++++++++++++++++++ 7 files changed, 214 insertions(+), 3 deletions(-) create mode 100755 bin/replQ create mode 100755 dist/bin/repl create mode 100644 dist/bin/repl.bat diff --git a/bin/replQ b/bin/replQ new file mode 100755 index 000000000000..5d0b84c4a229 --- /dev/null +++ b/bin/replQ @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" >& /dev/null && pwd)/.." +. $ROOT/bin/commonQ + +java -Dscala.usejavacp=true -cp $cp dotty.tools.repl.Main -usejavacp "$@" diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 8dfe72cf85d4..ac08c039c254 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -135,6 +135,7 @@ trait CommonScalaSettings: val usejavacp: Setting[Boolean] = BooleanSetting("-usejavacp", "Utilize the java.class.path in classpath resolution.", aliases = List("--use-java-class-path")) val scalajs: Setting[Boolean] = BooleanSetting("-scalajs", "Compile in Scala.js mode (requires scalajs-library.jar on the classpath).", aliases = List("--scalajs")) val replInitScript: Setting[String] = StringSetting("-repl-init-script", "code", "The code will be run on REPL startup.", "", aliases = List("--repl-init-script")) + val replEvalOnly: Setting[Boolean] = BooleanSetting("-repl-eval", "Quit REPL after evaluating the init script.", aliases = List("--repl-eval")) end CommonScalaSettings diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index bd97336fc792..492cc1f60c5a 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -139,7 +139,9 @@ class ReplDriver(settings: Array[String], * * Possible reason for unsuccessful run are raised flags in CLI like --help or --version */ - final def tryRunning = if shouldStart then runUntilQuit() + final def tryRunning = if shouldStart then + if rootCtx.settings.replEvalOnly.value(using rootCtx) then initialState + else runUntilQuit() /** Run REPL with `state` until `:quit` command found * diff --git a/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala b/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala index f2e64b5fad62..c76aa25ac84d 100644 --- a/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala +++ b/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala @@ -30,6 +30,7 @@ class BashExitCodeTests: def scala(args: String*) = verifyExit(scalaPath, args*) def scalacRaw(args: String*) = verifyExit(scalacPath, args*) def scalac(args: String*) = scalacRaw(("-d" +: tmpDir +: args)*) + def repl(args: String*) = verifyExit(replPath, args*) /** The path to the test file for this class. */ def f(body: String, suffix: String = ".scala"): String = @@ -62,6 +63,8 @@ class BashExitCodeTests: @Test def xPluginList = scala("-Xplugin-list")(0) @Test def vPhases = scala("-Vphases")(0) + @Test def replEval = repl("--repl-eval", "--repl-init-script", "\'println(\"Hello from init script!\"); val i = 2 * 2\'")(0) + /** A utility for running two commands in a row, like you do in bash. */ extension (inline u1: Unit) inline def & (inline u2: Unit): Unit = { u1; u2 } end BashExitCodeTests diff --git a/compiler/test/dotty/tools/scripting/ScriptTestEnv.scala b/compiler/test/dotty/tools/scripting/ScriptTestEnv.scala index 1db92d5415b4..7792ecb34239 100644 --- a/compiler/test/dotty/tools/scripting/ScriptTestEnv.scala +++ b/compiler/test/dotty/tools/scripting/ScriptTestEnv.scala @@ -234,10 +234,11 @@ object ScriptTestEnv { lazy val cwd: Path = Paths.get(".").toAbsolutePath.normalize - lazy val (scalacPath: String, scalaPath: String) = { + lazy val (scalacPath: String, scalaPath: String, replPath: String) = { val scalac = s"$workingDirectory/dist/target/pack/bin/scalac".toPath.normalize val scala = s"$workingDirectory/dist/target/pack/bin/scala".toPath.normalize - (scalac.norm, scala.norm) + val repl = s"$workingDirectory/dist/target/pack/bin/repl".toPath.normalize + (scalac.norm, scala.norm, repl.norm) } diff --git a/dist/bin/repl b/dist/bin/repl new file mode 100755 index 000000000000..e8f0f1bae93f --- /dev/null +++ b/dist/bin/repl @@ -0,0 +1,88 @@ +#!/usr/bin/env bash + +#set -o nounset ; set -o errexit + +# Try to autodetect real location of the script +if [ -z "${PROG_HOME-}" ] ; then + ## resolve links - $0 may be a link to PROG_HOME + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + PROG_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + PROG_HOME=`cd "$PROG_HOME" && pwd` + + cd "$saveddir" +fi + +source "$PROG_HOME/libexec/common" +default_java_opts="-Xmx768m -Xms768m" +withCompiler=true + +CompilerMain=dotty.tools.dotc.Main +DecompilerMain=dotty.tools.dotc.decompiler.Main +ReplMain=dotty.tools.repl.Main +ScriptingMain=dotty.tools.scripting.Main +JVM_CP_ARGS="$PROG_HOME/lib/scaladoc.jar" + +PROG_NAME=$CompilerMain + +addJava () { + java_args+=("'$1'") +} +addScala () { + scala_args+=("'$1'") +} +addResidual () { + residual_args+=("'$1'") +} +addScrip() { + script_args+=("'$1'") +} + +#for A in "$@" ; do echo "A[$A]" ; done ; exit 2 + +while [[ $# -gt 0 ]]; do +case "$1" in + --) shift; for arg; do addResidual "$arg"; done; set -- ;; + -v|-verbose) verbose=true && addScala "-verbose" && shift ;; + -q|-quiet) quiet=true && shift ;; + + -colors) colors=true && shift ;; + -no-colors) unset colors && shift ;; + # break out -D and -J options and add them to java_args so + # they reach the JVM in time to do some good. The -D options + # will be available as system properties. + -D*) addJava "$1" && shift ;; + -J*) addJava "${1:2}" && shift ;; + *) addResidual "$1" + shift + ;; + esac +done + +eval "\"$JAVACMD\"" \ + ${JAVA_OPTS:-$default_java_opts} \ + "${java_args[@]}" \ + -classpath "${JVM_CP_ARGS}" \ + -Dscala.expandjavacp=true \ + -Dscala.usejavacp=true \ + "dotty.tools.repl.Main" \ + "${scala_args[@]}" \ + "${residual_args[@]}" \ + "${scripting_string-}" +scala_exit_status=$? +onExit diff --git a/dist/bin/repl.bat b/dist/bin/repl.bat new file mode 100644 index 000000000000..5d710850c5ff --- /dev/null +++ b/dist/bin/repl.bat @@ -0,0 +1,110 @@ +@echo off +setlocal enabledelayedexpansion + +@rem ######################################################################### +@rem ## Environment setup + +set _EXITCODE=0 + +for %%f in ("%~dp0.") do ( + set "_PROG_HOME=%%~dpf" + @rem get rid of the trailing slash + set "_PROG_HOME=!_PROG_HOME:~0,-1!" +) +call "%_PROG_HOME%\libexec\common.bat" +if not %_EXITCODE%==0 goto end + +set _DEFAULT_JAVA_OPTS=-Xmx768m -Xms768m + +call :args %* + +@rem ######################################################################### +@rem ## Main + +if defined JAVA_OPTS ( set _JAVA_OPTS=%JAVA_OPTS% +) else ( set _JAVA_OPTS=%_DEFAULT_JAVA_OPTS% +) + +@rem we need to escape % in the java command path, for some reason this doesnt work in common.bat +set "_JAVACMD=!_JAVACMD:%%=%%%%!" + +call "%_JAVACMD%" %_JAVA_OPTS% %_JAVA_DEBUG% %_JAVA_ARGS% ^ +-classpath "%_LIB_DIR%\scaladoc.jar" ^ +-Dscala.expandjavacp=true ^ +-Dscala.usejavacp=true ^ +dotty.tools.repl.Main %_SCALA_ARGS% %_RESIDUAL_ARGS% +if not %ERRORLEVEL%==0 ( + @rem echo Error: Scaladoc execution failed 1>&2 + set _EXITCODE=1 + goto end +) +goto end + +@rem ######################################################################### +@rem ## Subroutines + +:args +set _JAVA_DEBUG= +set _HELP= +set _VERBOSE= +set _QUIET= +set _COLORS= +set _SCALA_ARGS= +set _JAVA_ARGS= +set _RESIDUAL_ARGS= + +:args_loop +if "%~1"=="" goto args_done +set "__ARG=%~1" +if "%__ARG%"=="--" ( + @rem for arg; do addResidual "$arg"; done; set -- ;; +) else if "%__ARG%"=="-h" ( + set _HELP=true + call :addScala "-help" +) else if "%__ARG%"=="-help" ( + set _HELP=true + call :addScala "-help" +) else if "%__ARG%"=="-v" ( + set _VERBOSE=true + call :addScala "-verbose" +) else if "%__ARG%"=="-verbose" ( + set _VERBOSE=true + call :addScala "-verbose" +) else if "%__ARG%"=="-debug" ( set "_JAVA_DEBUG=%_DEBUG_STR%" +) else if "%__ARG%"=="-q" ( set _QUIET=true +) else if "%__ARG%"=="-quiet" ( set _QUIET=true +) else if "%__ARG%"=="-colors" ( set _COLORS=true +) else if "%__ARG%"=="-no-colors" ( set _COLORS= +) else if "%__ARG:~0,2%"=="-D" ( call :addJava "%__ARG%" +) else if "%__ARG:~0,2%"=="-J" ( call :addJava "%__ARG:~2%" +) else ( + if defined _IN_SCRIPTING_ARGS ( call :addScripting "%__ARG%" + ) else ( call :addResidual "%__ARG%" + ) +) +shift +goto args_loop +:args_done +goto :eof + +@rem output parameter: _SCALA_ARGS +:addScala +set _SCALA_ARGS=%_SCALA_ARGS% %~1 +goto :eof + +@rem output parameter: _JAVA_ARGS +:addJava +set _JAVA_ARGS=%_JAVA_ARGS% %~1 +goto :eof + +@rem output parameter: _RESIDUAL_ARGS +:addResidual +set _RESIDUAL_ARGS=%_RESIDUAL_ARGS% %~1 +goto :eof + +@rem ######################################################################### +@rem ## Cleanups + +:end +exit /b %_EXITCODE% +endlocal From 4eff65527b981a91720beb3fa4826a0fcdd9081f Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Wed, 23 Apr 2025 11:11:52 +0200 Subject: [PATCH 126/505] Add REPL flag to quit after evaluating init script [Cherry-picked 1a9ba3a2cd555bd73b92148326e1a62d18ccb1f6][modified] From db49c88213e51fda8141880a3aee3c238c84f217 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Wed, 26 Feb 2025 13:49:42 +0100 Subject: [PATCH 127/505] Remove repl bin; rename flag --- .../tools/dotc/config/ScalaSettings.scala | 2 +- .../tools/scripting/BashExitCodeTests.scala | 4 +- .../dotty/tools/scripting/ScriptTestEnv.scala | 5 +- dist/bin/repl | 88 -------------- dist/bin/repl.bat | 110 ------------------ 5 files changed, 5 insertions(+), 204 deletions(-) delete mode 100755 dist/bin/repl delete mode 100644 dist/bin/repl.bat diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index ac08c039c254..9ad6b82984ec 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -135,7 +135,7 @@ trait CommonScalaSettings: val usejavacp: Setting[Boolean] = BooleanSetting("-usejavacp", "Utilize the java.class.path in classpath resolution.", aliases = List("--use-java-class-path")) val scalajs: Setting[Boolean] = BooleanSetting("-scalajs", "Compile in Scala.js mode (requires scalajs-library.jar on the classpath).", aliases = List("--scalajs")) val replInitScript: Setting[String] = StringSetting("-repl-init-script", "code", "The code will be run on REPL startup.", "", aliases = List("--repl-init-script")) - val replEvalOnly: Setting[Boolean] = BooleanSetting("-repl-eval", "Quit REPL after evaluating the init script.", aliases = List("--repl-eval")) + val replEvalOnly: Setting[Boolean] = BooleanSetting("-repl-quit-after-init", "Quit REPL after evaluating the init script.", aliases = List("--repl-quit-after-init")) end CommonScalaSettings diff --git a/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala b/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala index c76aa25ac84d..64ba94eac428 100644 --- a/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala +++ b/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala @@ -30,7 +30,7 @@ class BashExitCodeTests: def scala(args: String*) = verifyExit(scalaPath, args*) def scalacRaw(args: String*) = verifyExit(scalacPath, args*) def scalac(args: String*) = scalacRaw(("-d" +: tmpDir +: args)*) - def repl(args: String*) = verifyExit(replPath, args*) + def repl(args: String*) = verifyExit(scalaPath, "--power", "repl", "--offline", "--", args*) /** The path to the test file for this class. */ def f(body: String, suffix: String = ".scala"): String = @@ -63,7 +63,7 @@ class BashExitCodeTests: @Test def xPluginList = scala("-Xplugin-list")(0) @Test def vPhases = scala("-Vphases")(0) - @Test def replEval = repl("--repl-eval", "--repl-init-script", "\'println(\"Hello from init script!\"); val i = 2 * 2\'")(0) + @Test def replEval = repl("--repl-quit-after-init", "--repl-init-script", "\'println(\"Hello from init script!\"); val i = 2 * 2\'")(0) /** A utility for running two commands in a row, like you do in bash. */ extension (inline u1: Unit) inline def & (inline u2: Unit): Unit = { u1; u2 } diff --git a/compiler/test/dotty/tools/scripting/ScriptTestEnv.scala b/compiler/test/dotty/tools/scripting/ScriptTestEnv.scala index 7792ecb34239..1db92d5415b4 100644 --- a/compiler/test/dotty/tools/scripting/ScriptTestEnv.scala +++ b/compiler/test/dotty/tools/scripting/ScriptTestEnv.scala @@ -234,11 +234,10 @@ object ScriptTestEnv { lazy val cwd: Path = Paths.get(".").toAbsolutePath.normalize - lazy val (scalacPath: String, scalaPath: String, replPath: String) = { + lazy val (scalacPath: String, scalaPath: String) = { val scalac = s"$workingDirectory/dist/target/pack/bin/scalac".toPath.normalize val scala = s"$workingDirectory/dist/target/pack/bin/scala".toPath.normalize - val repl = s"$workingDirectory/dist/target/pack/bin/repl".toPath.normalize - (scalac.norm, scala.norm, repl.norm) + (scalac.norm, scala.norm) } diff --git a/dist/bin/repl b/dist/bin/repl deleted file mode 100755 index e8f0f1bae93f..000000000000 --- a/dist/bin/repl +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env bash - -#set -o nounset ; set -o errexit - -# Try to autodetect real location of the script -if [ -z "${PROG_HOME-}" ] ; then - ## resolve links - $0 may be a link to PROG_HOME - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - PROG_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - PROG_HOME=`cd "$PROG_HOME" && pwd` - - cd "$saveddir" -fi - -source "$PROG_HOME/libexec/common" -default_java_opts="-Xmx768m -Xms768m" -withCompiler=true - -CompilerMain=dotty.tools.dotc.Main -DecompilerMain=dotty.tools.dotc.decompiler.Main -ReplMain=dotty.tools.repl.Main -ScriptingMain=dotty.tools.scripting.Main -JVM_CP_ARGS="$PROG_HOME/lib/scaladoc.jar" - -PROG_NAME=$CompilerMain - -addJava () { - java_args+=("'$1'") -} -addScala () { - scala_args+=("'$1'") -} -addResidual () { - residual_args+=("'$1'") -} -addScrip() { - script_args+=("'$1'") -} - -#for A in "$@" ; do echo "A[$A]" ; done ; exit 2 - -while [[ $# -gt 0 ]]; do -case "$1" in - --) shift; for arg; do addResidual "$arg"; done; set -- ;; - -v|-verbose) verbose=true && addScala "-verbose" && shift ;; - -q|-quiet) quiet=true && shift ;; - - -colors) colors=true && shift ;; - -no-colors) unset colors && shift ;; - # break out -D and -J options and add them to java_args so - # they reach the JVM in time to do some good. The -D options - # will be available as system properties. - -D*) addJava "$1" && shift ;; - -J*) addJava "${1:2}" && shift ;; - *) addResidual "$1" - shift - ;; - esac -done - -eval "\"$JAVACMD\"" \ - ${JAVA_OPTS:-$default_java_opts} \ - "${java_args[@]}" \ - -classpath "${JVM_CP_ARGS}" \ - -Dscala.expandjavacp=true \ - -Dscala.usejavacp=true \ - "dotty.tools.repl.Main" \ - "${scala_args[@]}" \ - "${residual_args[@]}" \ - "${scripting_string-}" -scala_exit_status=$? -onExit diff --git a/dist/bin/repl.bat b/dist/bin/repl.bat deleted file mode 100644 index 5d710850c5ff..000000000000 --- a/dist/bin/repl.bat +++ /dev/null @@ -1,110 +0,0 @@ -@echo off -setlocal enabledelayedexpansion - -@rem ######################################################################### -@rem ## Environment setup - -set _EXITCODE=0 - -for %%f in ("%~dp0.") do ( - set "_PROG_HOME=%%~dpf" - @rem get rid of the trailing slash - set "_PROG_HOME=!_PROG_HOME:~0,-1!" -) -call "%_PROG_HOME%\libexec\common.bat" -if not %_EXITCODE%==0 goto end - -set _DEFAULT_JAVA_OPTS=-Xmx768m -Xms768m - -call :args %* - -@rem ######################################################################### -@rem ## Main - -if defined JAVA_OPTS ( set _JAVA_OPTS=%JAVA_OPTS% -) else ( set _JAVA_OPTS=%_DEFAULT_JAVA_OPTS% -) - -@rem we need to escape % in the java command path, for some reason this doesnt work in common.bat -set "_JAVACMD=!_JAVACMD:%%=%%%%!" - -call "%_JAVACMD%" %_JAVA_OPTS% %_JAVA_DEBUG% %_JAVA_ARGS% ^ --classpath "%_LIB_DIR%\scaladoc.jar" ^ --Dscala.expandjavacp=true ^ --Dscala.usejavacp=true ^ -dotty.tools.repl.Main %_SCALA_ARGS% %_RESIDUAL_ARGS% -if not %ERRORLEVEL%==0 ( - @rem echo Error: Scaladoc execution failed 1>&2 - set _EXITCODE=1 - goto end -) -goto end - -@rem ######################################################################### -@rem ## Subroutines - -:args -set _JAVA_DEBUG= -set _HELP= -set _VERBOSE= -set _QUIET= -set _COLORS= -set _SCALA_ARGS= -set _JAVA_ARGS= -set _RESIDUAL_ARGS= - -:args_loop -if "%~1"=="" goto args_done -set "__ARG=%~1" -if "%__ARG%"=="--" ( - @rem for arg; do addResidual "$arg"; done; set -- ;; -) else if "%__ARG%"=="-h" ( - set _HELP=true - call :addScala "-help" -) else if "%__ARG%"=="-help" ( - set _HELP=true - call :addScala "-help" -) else if "%__ARG%"=="-v" ( - set _VERBOSE=true - call :addScala "-verbose" -) else if "%__ARG%"=="-verbose" ( - set _VERBOSE=true - call :addScala "-verbose" -) else if "%__ARG%"=="-debug" ( set "_JAVA_DEBUG=%_DEBUG_STR%" -) else if "%__ARG%"=="-q" ( set _QUIET=true -) else if "%__ARG%"=="-quiet" ( set _QUIET=true -) else if "%__ARG%"=="-colors" ( set _COLORS=true -) else if "%__ARG%"=="-no-colors" ( set _COLORS= -) else if "%__ARG:~0,2%"=="-D" ( call :addJava "%__ARG%" -) else if "%__ARG:~0,2%"=="-J" ( call :addJava "%__ARG:~2%" -) else ( - if defined _IN_SCRIPTING_ARGS ( call :addScripting "%__ARG%" - ) else ( call :addResidual "%__ARG%" - ) -) -shift -goto args_loop -:args_done -goto :eof - -@rem output parameter: _SCALA_ARGS -:addScala -set _SCALA_ARGS=%_SCALA_ARGS% %~1 -goto :eof - -@rem output parameter: _JAVA_ARGS -:addJava -set _JAVA_ARGS=%_JAVA_ARGS% %~1 -goto :eof - -@rem output parameter: _RESIDUAL_ARGS -:addResidual -set _RESIDUAL_ARGS=%_RESIDUAL_ARGS% %~1 -goto :eof - -@rem ######################################################################### -@rem ## Cleanups - -:end -exit /b %_EXITCODE% -endlocal From fa115526960cf1088d75b1ab0aab2360e9a09397 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Wed, 23 Apr 2025 11:23:13 +0200 Subject: [PATCH 128/505] Remove repl bin; rename flag [Cherry-picked 28c877f74b919348f6d715ff01570aee8ee89822][modified] --- compiler/test/dotty/tools/scripting/BashExitCodeTests.scala | 3 --- 1 file changed, 3 deletions(-) diff --git a/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala b/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala index 64ba94eac428..f2e64b5fad62 100644 --- a/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala +++ b/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala @@ -30,7 +30,6 @@ class BashExitCodeTests: def scala(args: String*) = verifyExit(scalaPath, args*) def scalacRaw(args: String*) = verifyExit(scalacPath, args*) def scalac(args: String*) = scalacRaw(("-d" +: tmpDir +: args)*) - def repl(args: String*) = verifyExit(scalaPath, "--power", "repl", "--offline", "--", args*) /** The path to the test file for this class. */ def f(body: String, suffix: String = ".scala"): String = @@ -63,8 +62,6 @@ class BashExitCodeTests: @Test def xPluginList = scala("-Xplugin-list")(0) @Test def vPhases = scala("-Vphases")(0) - @Test def replEval = repl("--repl-quit-after-init", "--repl-init-script", "\'println(\"Hello from init script!\"); val i = 2 * 2\'")(0) - /** A utility for running two commands in a row, like you do in bash. */ extension (inline u1: Unit) inline def & (inline u2: Unit): Unit = { u1; u2 } end BashExitCodeTests From c93f4f4b30e5bfbc7d7110745c5c132dbfc3e808 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Wed, 23 Apr 2025 11:24:00 +0200 Subject: [PATCH 129/505] Fix arguments [Cherry-picked e8b1d1e163921d289f9f4a101ddfa9d76a853d5b][modified] From fce04dc4938c3681c750a167633a10693eb7bc46 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Thu, 27 Feb 2025 13:24:44 +0100 Subject: [PATCH 130/505] Rename setting name --- compiler/src/dotty/tools/dotc/config/ScalaSettings.scala | 2 +- compiler/src/dotty/tools/repl/ReplDriver.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 9ad6b82984ec..cfd20c95a76b 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -135,7 +135,7 @@ trait CommonScalaSettings: val usejavacp: Setting[Boolean] = BooleanSetting("-usejavacp", "Utilize the java.class.path in classpath resolution.", aliases = List("--use-java-class-path")) val scalajs: Setting[Boolean] = BooleanSetting("-scalajs", "Compile in Scala.js mode (requires scalajs-library.jar on the classpath).", aliases = List("--scalajs")) val replInitScript: Setting[String] = StringSetting("-repl-init-script", "code", "The code will be run on REPL startup.", "", aliases = List("--repl-init-script")) - val replEvalOnly: Setting[Boolean] = BooleanSetting("-repl-quit-after-init", "Quit REPL after evaluating the init script.", aliases = List("--repl-quit-after-init")) + val replQuitAfterInit: Setting[Boolean] = BooleanSetting("-repl-quit-after-init", "Quit REPL after evaluating the init script.", aliases = List("--repl-quit-after-init")) end CommonScalaSettings diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 492cc1f60c5a..282ad86efa32 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -140,7 +140,7 @@ class ReplDriver(settings: Array[String], * Possible reason for unsuccessful run are raised flags in CLI like --help or --version */ final def tryRunning = if shouldStart then - if rootCtx.settings.replEvalOnly.value(using rootCtx) then initialState + if rootCtx.settings.replQuitAfterInit.value(using rootCtx) then initialState else runUntilQuit() /** Run REPL with `state` until `:quit` command found From 9e48c64715500fdbe165ddf86cbce093285d20d8 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Wed, 23 Apr 2025 11:25:12 +0200 Subject: [PATCH 131/505] Rename setting name [Cherry-picked 7c4a701bd4a83398110423c4367f686bdee0da9f][modified] From ee6ea2481058d7efcffe7386fea7f926584c310d Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Wed, 23 Apr 2025 11:25:36 +0200 Subject: [PATCH 132/505] Update compiler/test/dotty/tools/scripting/BashExitCodeTests.scala Co-authored-by: Hamza Remmal [Cherry-picked fbd34ec3379e4f86f74f740be389e7720f1e0e87][modified] From cf181c29f12e87ec798aff3d4f729f52f49442fd Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Mon, 24 Feb 2025 07:08:53 -0800 Subject: [PATCH 133/505] Handle Typeable [Cherry-picked b52b0579d2192cfef689130cbbad8a07f1bc79f1] --- .../dotty/tools/dotc/core/Definitions.scala | 1 + .../tools/dotc/transform/CheckUnused.scala | 7 +++++-- tests/warn/i15503d.scala | 9 --------- tests/warn/i21525.scala | 18 +++++++++++++++++- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index f084e98e8806..da57315e15ff 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -811,6 +811,7 @@ class Definitions { @tu lazy val ReflectSelectableTypeRef: TypeRef = requiredClassRef("scala.reflect.Selectable") + @tu lazy val TypeableType: TypeSymbol = requiredPackage("scala.reflect.Typeable$package").moduleClass.requiredType("Typeable") @tu lazy val TypeTestClass: ClassSymbol = requiredClass("scala.reflect.TypeTest") @tu lazy val TypeTest_unapply: Symbol = TypeTestClass.requiredMethod(nme.unapply) @tu lazy val TypeTestModule_identity: Symbol = TypeTestClass.companionModule.requiredMethod(nme.identity) diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index f9bfbe680352..b40c07c78a62 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -68,8 +68,11 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha val name = tree.removeAttachment(OriginalName).getOrElse(nme.NO_NAME) if tree.srcPos.isSynthetic && tree.symbol == defn.TypeTest_unapply then tree.qualifier.tpe.underlying.finalResultType match - case AppliedType(_, args) => // tycon.typeSymbol == defn.TypeTestClass - val res = args(1) // T in TypeTest[-S, T] + case AppliedType(tycon, args) => + val res = + if tycon.typeSymbol == defn.TypeTestClass then args(1) // T in TypeTest[-S, T] + else if tycon.typeSymbol == defn.TypeableType then args(0) // T in Typeable[T] + else return tree val target = res.dealias.typeSymbol resolveUsage(target, target.name, res.importPrefix.skipPackageObject) // case _: T => case _ => diff --git a/tests/warn/i15503d.scala b/tests/warn/i15503d.scala index 494952e2e4b0..2981986daff6 100644 --- a/tests/warn/i15503d.scala +++ b/tests/warn/i15503d.scala @@ -1,7 +1,5 @@ //> using options -Wunused:patvars -import scala.reflect.Typeable - sealed trait Calc sealed trait Const extends Calc case class Sum(a: Calc, b: Calc) extends Calc @@ -74,13 +72,6 @@ class C(c0: Option[Int], k0: K): for case Some(value) <- List(Option(42)) yield 27 - /* - def tester[A](a: A)(using Typeable[K]) = - a match - case S(i, j) => i + j - case _ => 0 - */ - class Wild: def f(x: Any) = x match diff --git a/tests/warn/i21525.scala b/tests/warn/i21525.scala index aa156dc3960e..721486c4bd64 100644 --- a/tests/warn/i21525.scala +++ b/tests/warn/i21525.scala @@ -1,6 +1,7 @@ //> using options -Werror -Wunused:imports -import scala.reflect.TypeTest +import scala.reflect.{Typeable, TypeTest} +import compiletime.* trait A { type B @@ -18,3 +19,18 @@ def f(a: A, b: a.B): Boolean = { false } } + +trait T: + type X + given Typeable[X] = deferred + +def g(t: T, x: Any) = + import t.X + x match + case _: X => true + case _ => false + +def typer[T: Typeable](x: Any) = + x match + case _: T => 1 + case _ => 0 From 5abc895bd7842cf2928d136cbfbb155d3728deff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Bra=C4=8Devac?= Date: Sun, 2 Mar 2025 22:45:08 +0100 Subject: [PATCH 134/505] Repl: emit warning for the `:sh` command Fixes #21657 [Cherry-picked 9181b5588eae06ff3cfe7a35a415008fbd215bfe] --- compiler/src/dotty/tools/repl/ParseResult.scala | 7 +++++++ compiler/src/dotty/tools/repl/ReplDriver.scala | 4 ++++ compiler/test-resources/repl/i21657 | 2 ++ compiler/test/dotty/tools/repl/TabcompleteTests.scala | 1 + 4 files changed, 14 insertions(+) create mode 100644 compiler/test-resources/repl/i21657 diff --git a/compiler/src/dotty/tools/repl/ParseResult.scala b/compiler/src/dotty/tools/repl/ParseResult.scala index 2674a385a10c..dd4c5d80a9e1 100644 --- a/compiler/src/dotty/tools/repl/ParseResult.scala +++ b/compiler/src/dotty/tools/repl/ParseResult.scala @@ -100,6 +100,12 @@ object Reset { val command: String = ":reset" } +/** `:sh ` run a shell command (result is implicitly => List[String]) */ +case class Sh(expr: String) extends Command +object Sh { + val command: String = ":sh" +} + /** Toggle automatic printing of results */ case object Silent extends Command: val command: String = ":silent" @@ -150,6 +156,7 @@ object ParseResult { TypeOf.command -> (arg => TypeOf(arg)), DocOf.command -> (arg => DocOf(arg)), Settings.command -> (arg => Settings(arg)), + Sh.command -> (arg => Sh(arg)), Silent.command -> (_ => Silent), ) diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 282ad86efa32..114fa607f945 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -539,6 +539,10 @@ class ReplDriver(settings: Array[String], } state + case Sh(expr) => + out.println(s"""The :sh command is deprecated. Use `import scala.sys.process._` and `"command".!` instead.""") + state + case Settings(arg) => arg match case "" => given ctx: Context = state.context diff --git a/compiler/test-resources/repl/i21657 b/compiler/test-resources/repl/i21657 new file mode 100644 index 000000000000..fa2eec3ac891 --- /dev/null +++ b/compiler/test-resources/repl/i21657 @@ -0,0 +1,2 @@ +scala>:sh +The :sh command is deprecated. Use `import scala.sys.process._` and `"command".!` instead. \ No newline at end of file diff --git a/compiler/test/dotty/tools/repl/TabcompleteTests.scala b/compiler/test/dotty/tools/repl/TabcompleteTests.scala index 8c817dc2b96f..a881b828ec75 100644 --- a/compiler/test/dotty/tools/repl/TabcompleteTests.scala +++ b/compiler/test/dotty/tools/repl/TabcompleteTests.scala @@ -221,6 +221,7 @@ class TabcompleteTests extends ReplTest { ":quit", ":reset", ":settings", + ":sh", ":silent", ":type" ), From 352d41e221664169d2a7ca4b03270e8d391a5274 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Fri, 14 Feb 2025 16:12:24 +0000 Subject: [PATCH 135/505] Check exhaustivity of any case class --- .../dotty/tools/dotc/transform/patmat/Space.scala | 6 +----- i22590.arity2.scala | 15 +++++++++++++++ i22590.scala | 9 +++++++++ tests/pos/switches.scala | 1 + tests/warn/i15662.scala | 1 + tests/warn/opaque-match.scala | 2 ++ tests/{pos => warn}/t10373.scala | 4 ++-- 7 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 i22590.arity2.scala create mode 100644 i22590.scala rename tests/{pos => warn}/t10373.scala (74%) diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index 8f015bcd5f42..20b6a2e5b272 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -813,7 +813,6 @@ object SpaceEngine { } private def exhaustivityCheckable(sel: Tree)(using Context): Boolean = { - val seen = collection.mutable.Set.empty[Symbol] // Possible to check everything, but be compatible with scalac by default def isCheckable(tp: Type): Boolean = @@ -828,10 +827,7 @@ object SpaceEngine { }) || tpw.isRef(defn.BooleanClass) || classSym.isAllOf(JavaEnumTrait) || - classSym.is(Case) && { - if seen.add(classSym) then productSelectorTypes(tpw, sel.srcPos).exists(isCheckable(_)) - else true // recursive case class: return true and other members can still fail the check - } + classSym.is(Case) !sel.tpe.hasAnnotation(defn.UncheckedAnnot) && { diff --git a/i22590.arity2.scala b/i22590.arity2.scala new file mode 100644 index 000000000000..ddd126210cae --- /dev/null +++ b/i22590.arity2.scala @@ -0,0 +1,15 @@ +sealed trait T_B +case class CC_A() extends T_B +case class CC_C() extends T_B + +sealed trait T_A +case class CC_B[B](a: B,b:T_B) extends T_A + + +@main def test() = { + val v_a: CC_B[Int] = null + val v_b: Int = v_a match { + case CC_B(12, CC_A()) => 0 + case CC_B(_, CC_C()) => 0 + } +} diff --git a/i22590.scala b/i22590.scala new file mode 100644 index 000000000000..41d503ef8c6f --- /dev/null +++ b/i22590.scala @@ -0,0 +1,9 @@ +sealed trait T_A +case class CC_B[T](a: T) extends T_A + +@main def test() = { + val v_a: CC_B[Int] = CC_B(10) + val v_b: Int = v_a match{ + case CC_B(12) => 0 + } +} diff --git a/tests/pos/switches.scala b/tests/pos/switches.scala index bd7e44f1c8cf..beb378debb40 100644 --- a/tests/pos/switches.scala +++ b/tests/pos/switches.scala @@ -42,6 +42,7 @@ class Test { case IntAnyVal(100) => 2 case IntAnyVal(1000) => 3 case IntAnyVal(10000) => 4 + case _ => -1 } } diff --git a/tests/warn/i15662.scala b/tests/warn/i15662.scala index 0cf0e57ed0c3..f17a040b4980 100644 --- a/tests/warn/i15662.scala +++ b/tests/warn/i15662.scala @@ -5,6 +5,7 @@ case class Composite[T](v: T) def m(composite: Composite[?]): Unit = composite match { case Composite[Int](v) => println(v) // warn: cannot be checked at runtime + case _ => println("OTHER") } def m2(composite: Composite[?]): Unit = diff --git a/tests/warn/opaque-match.scala b/tests/warn/opaque-match.scala index 06cca835ab91..f66370def9b2 100644 --- a/tests/warn/opaque-match.scala +++ b/tests/warn/opaque-match.scala @@ -13,8 +13,10 @@ def Test[T] = case _: C => ??? // ok C() match case _: O.T => ??? // warn + case _ => ??? C() match case _: T => ??? // warn + case _ => ??? (??? : Any) match case _: List[O.T] => ??? // warn diff --git a/tests/pos/t10373.scala b/tests/warn/t10373.scala similarity index 74% rename from tests/pos/t10373.scala rename to tests/warn/t10373.scala index 0d91313f694d..ca49e7b1ce16 100644 --- a/tests/pos/t10373.scala +++ b/tests/warn/t10373.scala @@ -1,4 +1,4 @@ -//> using options -Xfatal-warnings -deprecation -feature +//> using options -deprecation -feature abstract class Foo { def bar(): Unit = this match { @@ -7,7 +7,7 @@ abstract class Foo { // Works fine } - def baz(that: Foo): Unit = (this, that) match { + def baz(that: Foo): Unit = (this, that) match { // warn: match may not be exhaustive. case (Foo_1(), _) => //do something case (Foo_2(), _) => //do something // match may not be exhaustive From d207772d9fecced7afa1bcf5033c43ff60a25450 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Wed, 23 Apr 2025 11:27:37 +0200 Subject: [PATCH 136/505] Check exhaustivity of any case class [Cherry-picked c00dda3d033b3a68333faeade691381c180c6873][modified] From e7ef5918400760ee30b02d8ab5c1e449f89fa496 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Mon, 17 Feb 2025 11:54:38 +0000 Subject: [PATCH 137/505] Fix fresh exhaustivity warnings in the compiler --- .../tools/backend/jvm/BCodeSkelBuilder.scala | 2 +- .../src/dotty/tools/dotc/core/Comments.scala | 13 ++--- .../dotty/tools/dotc/typer/Implicits.scala | 47 ++++++++++--------- 3 files changed, 29 insertions(+), 33 deletions(-) diff --git a/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala b/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala index 955597261327..437a34a53902 100644 --- a/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala +++ b/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala @@ -169,7 +169,7 @@ trait BCodeSkelBuilder extends BCodeHelpers { /* ---------------- helper utils for generating classes and fields ---------------- */ - def genPlainClass(cd0: TypeDef) = cd0 match { + def genPlainClass(cd0: TypeDef) = (cd0: @unchecked) match { case TypeDef(_, impl: Template) => assert(cnode == null, "GenBCode detected nested methods.") diff --git a/compiler/src/dotty/tools/dotc/core/Comments.scala b/compiler/src/dotty/tools/dotc/core/Comments.scala index 92160c97973d..b1d1e387c2cf 100644 --- a/compiler/src/dotty/tools/dotc/core/Comments.scala +++ b/compiler/src/dotty/tools/dotc/core/Comments.scala @@ -405,15 +405,10 @@ object Comments { val Trim = "(?s)^[\\s&&[^\n\r]]*(.*?)\\s*$".r val raw = ctx.docCtx.flatMap(_.docstring(sym).map(_.raw)).getOrElse("") - defs(sym) ++= defines(raw).map { - str => { - val start = skipWhitespace(str, "@define".length) - val (key, value) = str.splitAt(skipVariable(str, start)) - key.drop(start) -> value - } - } map { - case (key, Trim(value)) => - variableName(key) -> value.replaceAll("\\s+\\*+$", "") + defs(sym) ++= defines(raw).map { str => + val start = skipWhitespace(str, "@define".length) + val (key, Trim(value)) = str.splitAt(skipVariable(str, start)): @unchecked + variableName(key.drop(start)) -> value.replaceAll("\\s+\\*+$", "") } } diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 69237c2aa493..a1a01823e2f3 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -1290,29 +1290,30 @@ trait Implicits: if alt1.isExtension then // Fall back: if both results are extension method applications, // compare the extension methods instead of their wrappers. - def stripExtension(alt: SearchSuccess) = methPart(stripApply(alt.tree)).tpe - (stripExtension(alt1), stripExtension(alt2)) match - case (ref1: TermRef, ref2: TermRef) => - // ref1 and ref2 might refer to type variables owned by - // alt1.tstate and alt2.tstate respectively, to compare the - // alternatives correctly we need a TyperState that includes - // constraints from both sides, see - // tests/*/extension-specificity2.scala for test cases. - val constraintsIn1 = alt1.tstate.constraint ne ctx.typerState.constraint - val constraintsIn2 = alt2.tstate.constraint ne ctx.typerState.constraint - def exploreState(alt: SearchSuccess): TyperState = - alt.tstate.fresh(committable = false) - val comparisonState = - if constraintsIn1 && constraintsIn2 then - exploreState(alt1).mergeConstraintWith(alt2.tstate) - else if constraintsIn1 then - exploreState(alt1) - else if constraintsIn2 then - exploreState(alt2) - else - ctx.typerState - - diff = inContext(ctx.withTyperState(comparisonState)): + def stripExtension(alt: SearchSuccess) = + methPart(stripApply(alt.tree)).tpe: @unchecked match { case ref: TermRef => ref } + val ref1 = stripExtension(alt1) + val ref2 = stripExtension(alt2) + // ref1 and ref2 might refer to type variables owned by + // alt1.tstate and alt2.tstate respectively, to compare the + // alternatives correctly we need a TyperState that includes + // constraints from both sides, see + // tests/*/extension-specificity2.scala for test cases. + val constraintsIn1 = alt1.tstate.constraint ne ctx.typerState.constraint + val constraintsIn2 = alt2.tstate.constraint ne ctx.typerState.constraint + def exploreState(alt: SearchSuccess): TyperState = + alt.tstate.fresh(committable = false) + val comparisonState = + if constraintsIn1 && constraintsIn2 then + exploreState(alt1).mergeConstraintWith(alt2.tstate) + else if constraintsIn1 then + exploreState(alt1) + else if constraintsIn2 then + exploreState(alt2) + else + ctx.typerState + + diff = inContext(ctx.withTyperState(comparisonState)): compare(ref1, ref2) else // alt1 is a conversion, prefer extension alt2 over it diff = -1 From 2d612911b6e808ec88bd437e79cd8ae96e51eaf5 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Wed, 23 Apr 2025 11:29:16 +0200 Subject: [PATCH 138/505] Fix fresh exhaustivity warnings in the compiler [Cherry-picked 4072218f4d956d90ca9d50aaf0793ef3e77664dd][modified] From 52e811c0ef6b4485df3192df12c130a798ebf443 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Wed, 23 Apr 2025 11:30:43 +0200 Subject: [PATCH 139/505] Fix fresh exhaustivity warnings in scaladoc [Cherry-picked daa31fd0f598a48df8a2c64392fc76519e0d490f][modified] --- scaladoc/src/dotty/tools/scaladoc/site/templates.scala | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/site/templates.scala b/scaladoc/src/dotty/tools/scaladoc/site/templates.scala index 92e0096e5af1..56a0f7f6d6b6 100644 --- a/scaladoc/src/dotty/tools/scaladoc/site/templates.scala +++ b/scaladoc/src/dotty/tools/scaladoc/site/templates.scala @@ -102,11 +102,9 @@ case class TemplateFile( ctx.layouts.getOrElse(name, throw new RuntimeException(s"No layouts named $name in ${ctx.layouts}")) ) - def asJavaElement(o: Object): Object = o match - case m: Map[_, _] => m.transform { - case (k: String, v: Object) => asJavaElement(v) - }.asJava - case l: List[_] => l.map(x => asJavaElement(x.asInstanceOf[Object])).asJava + def asJavaElement(o: Any): Any = o match + case m: Map[?, ?] => m.transform { (k, v) => asJavaElement(v) }.asJava + case l: List[?] => l.map(asJavaElement).asJava case other => other // Library requires mutable maps.. From 3ec2223bc843c0f6a1422334ca1a28907b62bb91 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Tue, 18 Feb 2025 10:10:31 +0000 Subject: [PATCH 140/505] Move exh checking case class tests in [Cherry-picked 892f048594b65e22498291f388daf4554a315ffe] --- library/src/scala/annotation/newMain.scala | 1 + i22590.arity2.scala => tests/warn/i22590.arity2.scala | 2 +- i22590.scala => tests/warn/i22590.scala | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) rename i22590.arity2.scala => tests/warn/i22590.arity2.scala (79%) rename i22590.scala => tests/warn/i22590.scala (67%) diff --git a/library/src/scala/annotation/newMain.scala b/library/src/scala/annotation/newMain.scala index 552e4225a648..686f3bf14b54 100644 --- a/library/src/scala/annotation/newMain.scala +++ b/library/src/scala/annotation/newMain.scala @@ -253,6 +253,7 @@ final class newMain extends MainAnnotation[FromString, Any]: case (arg +: t, "") => recurse(t, arg, acc) case (arg +: t, l) if l.length + 1 + arg.length <= maxLength => recurse(t, s"$l $arg", acc) case (arg +: t, l) => recurse(t, arg, acc :+ l) + case (_, _) => acc } recurse(argsUsage, "", Vector()).toList diff --git a/i22590.arity2.scala b/tests/warn/i22590.arity2.scala similarity index 79% rename from i22590.arity2.scala rename to tests/warn/i22590.arity2.scala index ddd126210cae..8ce84ab299f1 100644 --- a/i22590.arity2.scala +++ b/tests/warn/i22590.arity2.scala @@ -8,7 +8,7 @@ case class CC_B[B](a: B,b:T_B) extends T_A @main def test() = { val v_a: CC_B[Int] = null - val v_b: Int = v_a match { + val v_b: Int = v_a match { // warn: match may not be exhaustive. case CC_B(12, CC_A()) => 0 case CC_B(_, CC_C()) => 0 } diff --git a/i22590.scala b/tests/warn/i22590.scala similarity index 67% rename from i22590.scala rename to tests/warn/i22590.scala index 41d503ef8c6f..1520a07b86b8 100644 --- a/i22590.scala +++ b/tests/warn/i22590.scala @@ -3,7 +3,7 @@ case class CC_B[T](a: T) extends T_A @main def test() = { val v_a: CC_B[Int] = CC_B(10) - val v_b: Int = v_a match{ + val v_b: Int = v_a match{ // warn: match may not be exhaustive. case CC_B(12) => 0 } } From e15b83a6ee8e61a6f6be19630fa5c666efcb5864 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Wed, 23 Apr 2025 13:34:25 +0200 Subject: [PATCH 141/505] chore: Adjust test output --- tests/warn/i21218.scala | 1 + tests/warn/i21525.scala | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/warn/i21218.scala b/tests/warn/i21218.scala index 29fa957e2e70..db0810c5d7b0 100644 --- a/tests/warn/i21218.scala +++ b/tests/warn/i21218.scala @@ -6,5 +6,6 @@ def Test[U, A](thisElem: A, thatElem: U) = { case (`passedEnd`, r: U @unchecked) => (thisElem, r) case (l: A @unchecked, `passedEnd`) => (l, thatElem) case t: (A, U) @unchecked => t // false-positive warning + case (t1, t2) => (t1, t2) } } diff --git a/tests/warn/i21525.scala b/tests/warn/i21525.scala index 721486c4bd64..71b6fbe1ce48 100644 --- a/tests/warn/i21525.scala +++ b/tests/warn/i21525.scala @@ -22,7 +22,7 @@ def f(a: A, b: a.B): Boolean = { trait T: type X - given Typeable[X] = deferred + given tpe: Typeable[X] def g(t: T, x: Any) = import t.X From 8b2f2c31c04c136cf4d8a5c37abe790805e40f95 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Wed, 23 Apr 2025 13:48:37 +0200 Subject: [PATCH 142/505] chore: Add back repl test using bin/scala --- compiler/test/dotty/tools/scripting/BashExitCodeTests.scala | 3 +++ tests/warn/i21525.scala | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala b/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala index f2e64b5fad62..3aad9ef8813f 100644 --- a/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala +++ b/compiler/test/dotty/tools/scripting/BashExitCodeTests.scala @@ -62,6 +62,9 @@ class BashExitCodeTests: @Test def xPluginList = scala("-Xplugin-list")(0) @Test def vPhases = scala("-Vphases")(0) + @Test def replEval = + scala("--repl-quit-after-init", "--repl-init-script", "'val i = 2 * 2; val j = i + 2'")(0) + /** A utility for running two commands in a row, like you do in bash. */ extension (inline u1: Unit) inline def & (inline u2: Unit): Unit = { u1; u2 } end BashExitCodeTests diff --git a/tests/warn/i21525.scala b/tests/warn/i21525.scala index 71b6fbe1ce48..7fecb14a9673 100644 --- a/tests/warn/i21525.scala +++ b/tests/warn/i21525.scala @@ -1,7 +1,6 @@ //> using options -Werror -Wunused:imports import scala.reflect.{Typeable, TypeTest} -import compiletime.* trait A { type B From 511e8d2b1614a3aba6e60c02c4136e5cf1871aee Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Sun, 2 Mar 2025 20:01:45 -0800 Subject: [PATCH 143/505] Exclude synthetic this.m, Any.m from import lookup [Cherry-picked fb1fe22611088629e48b66ef9258cd1bb639fd5f] --- .../src/dotty/tools/dotc/transform/CheckUnused.scala | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index b40c07c78a62..22d27cb61c66 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -66,6 +66,10 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha // import x.y; y may be rewritten x.y, also import x.z as y override def transformSelect(tree: Select)(using Context): tree.type = val name = tree.removeAttachment(OriginalName).getOrElse(nme.NO_NAME) + inline def isImportable = tree.qualifier.srcPos.isSynthetic + && tree.qualifier.tpe.match + case ThisType(_) | SuperType(_, _) => false + case qualtpe => qualtpe.isStable if tree.srcPos.isSynthetic && tree.symbol == defn.TypeTest_unapply then tree.qualifier.tpe.underlying.finalResultType match case AppliedType(tycon, args) => @@ -76,10 +80,10 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha val target = res.dealias.typeSymbol resolveUsage(target, target.name, res.importPrefix.skipPackageObject) // case _: T => case _ => - else if tree.qualifier.srcPos.isSynthetic && tree.qualifier.tpe.isStable || name.exists(_ != tree.symbol.name) then + else if isImportable || name.exists(_ != tree.symbol.name) then if !ignoreTree(tree) then resolveUsage(tree.symbol, name, tree.qualifier.tpe) - else + else if !ignoreTree(tree) then refUsage(tree.symbol) tree @@ -304,7 +308,8 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha case none => // Avoid spurious NoSymbol and also primary ctors which are never warned about. - if !sym.exists || sym.isPrimaryConstructor then return + // Selections C.this.toString should be already excluded, but backtopped here for eq, etc. + if !sym.exists || sym.isPrimaryConstructor || defn.topClasses(sym.owner) then return // Find the innermost, highest precedence. Contexts have no nesting levels but assume correctness. // If the sym is an enclosing definition (the owner of a context), it does not count toward usages. @@ -442,7 +447,6 @@ object CheckUnused: if (tree.symbol ne NoSymbol) && !tree.name.isWildcard then defs.addOne((tree.symbol, tree.namePos)) case _ => - //println(s"OTHER ${tree.symbol}") if tree.symbol ne NoSymbol then defs.addOne((tree.symbol, tree.srcPos)) From 617efc92531624ca6af957829a98a8754478a588 Mon Sep 17 00:00:00 2001 From: Jan Chyb Date: Mon, 24 Feb 2025 15:49:49 +0100 Subject: [PATCH 144/505] Fix stale symbol crash on classes with package owner [Cherry-picked b5a31512de1352be73df52612e13d422b19f5eff] --- compiler/src/dotty/tools/dotc/typer/Namer.scala | 2 +- tests/pos-macros/i20449/Macro.scala | 3 +++ tests/pos-macros/i20449/Main.scala | 6 ++++++ 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 tests/pos-macros/i20449/Macro.scala create mode 100644 tests/pos-macros/i20449/Main.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index cea045cecc35..4bdee42069d0 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -694,7 +694,7 @@ class Namer { typer: Typer => enterSymbol(classConstructorCompanion(classSym.asClass)) else for moduleSym <- companionVals do - if moduleSym.is(Module) && !moduleSym.isDefinedInCurrentRun then + if moduleSym.lastKnownDenotation.is(Module) && !moduleSym.isDefinedInCurrentRun then val companion = if needsConstructorProxies(classSym) then classConstructorCompanion(classSym.asClass) diff --git a/tests/pos-macros/i20449/Macro.scala b/tests/pos-macros/i20449/Macro.scala new file mode 100644 index 000000000000..56c9a625e894 --- /dev/null +++ b/tests/pos-macros/i20449/Macro.scala @@ -0,0 +1,3 @@ +import scala.quoted.* +transparent inline def getTypeInfo[T]() = ${ getTypeInfoImpl[T] } +def getTypeInfoImpl[T: Type](using ctx: Quotes): Expr[Unit] = '{ () } diff --git a/tests/pos-macros/i20449/Main.scala b/tests/pos-macros/i20449/Main.scala new file mode 100644 index 000000000000..7c1a71c5598e --- /dev/null +++ b/tests/pos-macros/i20449/Main.scala @@ -0,0 +1,6 @@ + +class Wrapper1[A] +val a = { + getTypeInfo[Any]() + val wrapper2 = Wrapper1[Any]() +} \ No newline at end of file From dd924329020abf2230dc2a5b469319de6353b2f0 Mon Sep 17 00:00:00 2001 From: Jan Chyb Date: Mon, 24 Feb 2025 15:52:09 +0100 Subject: [PATCH 145/505] Fix opaque type implementations being exposed when in type params [Cherry-picked 09f13d58e169c957b4bb0c19722f1730dc208f63] --- .../dotty/tools/dotc/inlines/Inliner.scala | 12 ++++- tests/pos-macros/i20449/Main.scala | 2 +- tests/run-macros/i20449.check | 50 +++++++++++++++++++ tests/run-macros/i20449/Macro_1.scala | 29 +++++++++++ tests/run-macros/i20449/Main_2.scala | 41 +++++++++++++++ 5 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 tests/run-macros/i20449.check create mode 100644 tests/run-macros/i20449/Macro_1.scala create mode 100644 tests/run-macros/i20449/Main_2.scala diff --git a/compiler/src/dotty/tools/dotc/inlines/Inliner.scala b/compiler/src/dotty/tools/dotc/inlines/Inliner.scala index 7e9e4498e310..4404ae9f9ea4 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inliner.scala @@ -399,7 +399,17 @@ class Inliner(val call: tpd.Tree)(using Context): * type aliases, add proxy definitions to `opaqueProxies` that expose these aliases. */ private def addOpaqueProxies(tp: Type, span: Span, forThisProxy: Boolean)(using Context): Unit = - tp.foreachPart { + val foreachTpPart = + (p: Type => Unit) => + if forThisProxy then + // Performs operations on all parts of this type, outside of the applied type arguments + new ForeachAccumulator(p, StopAt.None) { + override def apply(x: Unit, tp: Type) = tp match + case AppliedType(tycon, _) => super.apply(x, tycon) + case other => super.apply(x, other) + }.apply((), tp) + else tp.foreachPart(p) + foreachTpPart { case ref: TermRef => for cls <- ref.widen.baseClasses do if cls.containsOpaques diff --git a/tests/pos-macros/i20449/Main.scala b/tests/pos-macros/i20449/Main.scala index 7c1a71c5598e..c6f5c0b05b69 100644 --- a/tests/pos-macros/i20449/Main.scala +++ b/tests/pos-macros/i20449/Main.scala @@ -3,4 +3,4 @@ class Wrapper1[A] val a = { getTypeInfo[Any]() val wrapper2 = Wrapper1[Any]() -} \ No newline at end of file +} diff --git a/tests/run-macros/i20449.check b/tests/run-macros/i20449.check new file mode 100644 index 000000000000..289b3f95c488 --- /dev/null +++ b/tests/run-macros/i20449.check @@ -0,0 +1,50 @@ +------ UserName.T - Directly ------- +Original: Main_2$package.UserName.T +Dealias: Main_2$package.UserName.T +Dealias dealias: Main_2$package.UserName.T + +------ UserName.T - Directly ------- +Original: Main_2$package.UserName +Dealias: Main_2$package.UserName.T +Dealias dealias: Main_2$package.UserName.T + +------ ForeignWrapper1[UserName.T] ------- +Original: Main_2$package.UserName.T +Dealias: Main_2$package.UserName.T +Dealias dealias: Main_2$package.UserName.T + +------ ForeignWrapper2[UserName.T] ------- +Original: Main_2$package.UserName.T +Dealias: Main_2$package.UserName.T +Dealias dealias: Main_2$package.UserName.T + +------ ForeignWrapper1[UserName] ------- +Original: Main_2$package.UserName +Dealias: Main_2$package.UserName.T +Dealias dealias: Main_2$package.UserName.T + +------ ForeignWrapper2[UserName] ------- +Original: Main_2$package.UserName +Dealias: Main_2$package.UserName.T +Dealias dealias: Main_2$package.UserName.T + +------ Wrapper1[UserName.T] ------- +Original: Main_2$package.UserName.T +Dealias: Main_2$package.UserName.T +Dealias dealias: Main_2$package.UserName.T + +------ Wrapper2[UserName.T] ------- +Original: Main_2$package.UserName.T +Dealias: Main_2$package.UserName.T +Dealias dealias: Main_2$package.UserName.T + +------ Wrapper1[UserName] ------- +Original: Main_2$package.UserName +Dealias: Main_2$package.UserName.T +Dealias dealias: Main_2$package.UserName.T + +------ Wrapper2[UserName] ------- +Original: Main_2$package.UserName +Dealias: Main_2$package.UserName.T +Dealias dealias: Main_2$package.UserName.T + diff --git a/tests/run-macros/i20449/Macro_1.scala b/tests/run-macros/i20449/Macro_1.scala new file mode 100644 index 000000000000..74b1dce3c4d6 --- /dev/null +++ b/tests/run-macros/i20449/Macro_1.scala @@ -0,0 +1,29 @@ +import scala.quoted.* + +class ForeignWrapper1[-A] { + inline def getTypeInfo(inline source: String): String = + ${ getTypeInfoImpl[A]('source) } + def createWrapper2 = ForeignWrapper2(this) +} + +class ForeignWrapper2[-A](val self: ForeignWrapper1[A]) { + inline def getTypeInfo(inline source: String): String = + ${getTypeInfoImpl[A]('source)} +} + +transparent inline def getTypeInfo[T](inline source: String) = + ${ getTypeInfoImpl[T]('source) } + +def getTypeInfoImpl[T: Type](source: Expr[String])(using ctx: Quotes) : Expr[String] = { + import ctx.reflect.* + + val tpe = TypeRepr.of[T] + val str = + s"""|------ ${source.valueOrAbort} ------- + |Original: ${tpe.show} + |Dealias: ${tpe.dealias.show} + |Dealias dealias: ${tpe.dealias.dealias.show} + """.stripMargin + + Expr(str) +} diff --git a/tests/run-macros/i20449/Main_2.scala b/tests/run-macros/i20449/Main_2.scala new file mode 100644 index 000000000000..3d2991489c1b --- /dev/null +++ b/tests/run-macros/i20449/Main_2.scala @@ -0,0 +1,41 @@ +object UserName { + opaque type T = String + + def apply(s: String): T = s +} + +type UserName = UserName.T + +class Wrapper1[-A] { + inline def getTypeInfo(inline source: String): String = + ${ getTypeInfoImpl[A]('source) } + def createWrapper2 = Wrapper2(this) +} + +class Wrapper2[-A](val self: Wrapper1[A]) { + inline def getTypeInfo(inline source: String): String = + ${getTypeInfoImpl[A]('source)} +} + + +@main def Test() = { + println(getTypeInfo[UserName.T]("UserName.T - Directly")) + println(getTypeInfo[UserName]("UserName.T - Directly")) + + val foreignWrapper = ForeignWrapper1[UserName.T]() + println(foreignWrapper.getTypeInfo("ForeignWrapper1[UserName.T]")) + println(foreignWrapper.createWrapper2.getTypeInfo("ForeignWrapper2[UserName.T]")) + + val foreignWrapper2 = ForeignWrapper1[UserName]() + println(foreignWrapper2.getTypeInfo("ForeignWrapper1[UserName]")) + println(foreignWrapper2.createWrapper2.getTypeInfo("ForeignWrapper2[UserName]")) + + val wrapper = Wrapper1[UserName.T]() + println(wrapper.getTypeInfo("Wrapper1[UserName.T]")) + println(wrapper.createWrapper2.getTypeInfo("Wrapper2[UserName.T]")) + + val wrapper2 = Wrapper1[UserName]() + println(wrapper2.getTypeInfo("Wrapper1[UserName]")) + println(wrapper2.createWrapper2.getTypeInfo("Wrapper2[UserName]")) + +} From 504574d94a76d57b94f87afca6f89b44950ceba0 Mon Sep 17 00:00:00 2001 From: Jan Chyb Date: Mon, 3 Mar 2025 14:15:49 +0100 Subject: [PATCH 146/505] Add a comment explaining the stale symbol fix [Cherry-picked 23911dfbbf1f92e41d6d43e50d1216889841858a] --- compiler/src/dotty/tools/dotc/typer/Namer.scala | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 4bdee42069d0..a47a0a61c9d4 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -694,6 +694,12 @@ class Namer { typer: Typer => enterSymbol(classConstructorCompanion(classSym.asClass)) else for moduleSym <- companionVals do + // by not going through `.lastKnownDenotation` (instead using `.current`), + // we guarantee that the `moduleSym` will be brought forward to the current run, + // rendering `moduleSym.isDefinedInCurrentRun` as always true. + // We want to regenerate the companion instead of bringing it forward, + // as even if we are able to bring forward the object symbol, + // we might not be able to do the same with its stale module class symbol (see `tests/pos/i20449`) if moduleSym.lastKnownDenotation.is(Module) && !moduleSym.isDefinedInCurrentRun then val companion = if needsConstructorProxies(classSym) then From 8e6a37d04ef1ef827a6a47d82b43250884013c63 Mon Sep 17 00:00:00 2001 From: Felix Herrmann Date: Mon, 7 Oct 2024 18:55:42 +0200 Subject: [PATCH 147/505] Fix #21721: make case TypeBlock(_, _) not match non-type Block TypeBlocks are represented as normal Blocks in the Quotes API. The current TypeTest for TypeBlock is exactly the same as the TypeTest for Block, which means that case TypeBlock(_, _) matches every block. The implementation of unapply on TypeBlockModule, however, gives back (List[TypeDef], TypeTree). It constructs the List[TypeDef] by mapping over every statement, turning it into a TypeDef by using a match with the pattern case alias: TypeDef => alias Since the TypeTest matches any Block and not only Blocks that are TypeBlocks, the statemnts can be anything, not just TypeDefs, which lets the whole case TypeBlock(_, _) pattern fail with a MatchError. This commit fixes the problem by making the TypeTest check whether the Block is a type (which in turns checks whether the blocks expression is a type) [Cherry-picked 147f5622f822d5084fe03420cb0e2a6d593856ff] --- .../src/scala/quoted/runtime/impl/QuotesImpl.scala | 2 +- tests/pos/i21721/Macro.scala | 12 ++++++++++++ tests/pos/i21721/Test.scala | 5 +++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 tests/pos/i21721/Macro.scala create mode 100644 tests/pos/i21721/Test.scala diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index f5a201de1f2e..a1673f017cd7 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -1390,7 +1390,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler object TypeBlockTypeTest extends TypeTest[Tree, TypeBlock]: def unapply(x: Tree): Option[TypeBlock & x.type] = x match - case tpt: (tpd.Block & x.type) => Some(tpt) + case tpt: (tpd.Block & x.type) if x.isType => Some(tpt) case _ => None end TypeBlockTypeTest diff --git a/tests/pos/i21721/Macro.scala b/tests/pos/i21721/Macro.scala new file mode 100644 index 000000000000..dfdbff6a659b --- /dev/null +++ b/tests/pos/i21721/Macro.scala @@ -0,0 +1,12 @@ +import quoted.* + +object Macro: + inline def impl(inline expr: Any): Any = + ${implImpl('expr)} + + def implImpl(expr: Expr[Any])(using q: Quotes): Expr[Any] = + import q.reflect.* + expr.asTerm.asInstanceOf[Inlined].body match + // this should not fail with a MatchError + case TypeBlock(_, _) => '{ "TypeBlock" } + case _ => '{ "Nothing" } diff --git a/tests/pos/i21721/Test.scala b/tests/pos/i21721/Test.scala new file mode 100644 index 000000000000..ebe91bae9ef4 --- /dev/null +++ b/tests/pos/i21721/Test.scala @@ -0,0 +1,5 @@ +object Test: + // give a Block(...) to the macro + Macro.impl: + val a = 3 + a From 87eff62a9c66158c7b6361babd573ccc211ebcf5 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Mon, 3 Mar 2025 12:28:04 +0000 Subject: [PATCH 148/505] Revert lambda cleanup (but keep remaining changes) Reverts PR 21466, but keeps the other changes in that PR and in the abandoned attempt that is PR 22031. Fixes issue 21981, by virtue of rebasing. [Cherry-picked 28c1ae3f75e06b82f6e9ec9000292fb93d3db366] --- .../tools/dotc/core/OrderingConstraint.scala | 10 +- .../dotty/tools/dotc/typer/Inferencing.scala | 252 +++++++++--------- .../dotty/tools/dotc/typer/ProtoTypes.scala | 7 - tests/pos/i21981.alt.scala | 24 ++ tests/pos/i21981.contrak.scala | 27 ++ tests/pos/i21981.orig.scala | 29 ++ tests/pos/i21981.scala | 24 ++ 7 files changed, 236 insertions(+), 137 deletions(-) create mode 100644 tests/pos/i21981.alt.scala create mode 100644 tests/pos/i21981.contrak.scala create mode 100644 tests/pos/i21981.orig.scala create mode 100644 tests/pos/i21981.scala diff --git a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala index c9b60ac051ad..78c717539763 100644 --- a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala +++ b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala @@ -263,9 +263,9 @@ class OrderingConstraint(private val boundsMap: ParamBounds, private var coDeps: ReverseDeps = SimpleIdentityMap.empty /** A map that associates type parameters of this constraint with all other type - * parameters that refer to them in their bounds covariantly, such that, if the + * parameters that refer to them in their bounds contravariantly, such that, if the * type parameter is instantiated to a smaller type, the constraint would be narrowed. - * (i.e. solution set changes other than simply being made larger). + * (i.e. solution set changes other than simply being made smaller). */ private var contraDeps: ReverseDeps = SimpleIdentityMap.empty @@ -368,7 +368,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds, /** Adjust reverse dependencies of all type parameters referenced by `bound` * @param isLower `bound` is a lower bound - * @param add if true, add referenced variables to dependencoes, otherwise drop them. + * @param add if true, add referenced variables to dependencies, otherwise drop them. */ def adjustReferenced(bound: Type, isLower: Boolean, add: Boolean) = adjuster.variance = if isLower then 1 else -1 @@ -394,8 +394,8 @@ class OrderingConstraint(private val boundsMap: ParamBounds, } case _ => false - /** Add or remove depenencies referenced in `bounds`. - * @param add if true, dependecies are added, otherwise they are removed + /** Add or remove dependencies referenced in `bounds`. + * @param add if true, dependencies are added, otherwise they are removed */ def adjustBounds(bounds: TypeBounds, add: Boolean) = adjustReferenced(bounds.lo, isLower = true, add) diff --git a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala index 7acc704fd00d..877c6d36d3e9 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala @@ -604,7 +604,6 @@ trait Inferencing { this: Typer => // This is needed because it could establish singleton type upper bounds. See i2998.scala. val tp = tree.tpe.widen - val vs = variances(tp, pt) // Avoid interpolating variables occurring in tree's type if typerstate has unreported errors. // Reason: The errors might reflect unsatisfiable constraints. In that @@ -628,135 +627,138 @@ trait Inferencing { this: Typer => // val y: List[List[String]] = List(List(1)) if state.reporter.hasUnreportedErrors then return tree - def constraint = state.constraint - - trace(i"interpolateTypeVars($tree: ${tree.tpe}, $pt, $qualifying)", typr, (_: Any) => i"$qualifying\n$constraint\n${ctx.gadt}") { - //println(i"$constraint") - //println(i"${ctx.gadt}") - - /** Values of this type report type variables to instantiate with variance indication: - * +1 variable appears covariantly, can be instantiated from lower bound - * -1 variable appears contravariantly, can be instantiated from upper bound - * 0 variable does not appear at all, can be instantiated from either bound - */ - type ToInstantiate = List[(TypeVar, Int)] - - val toInstantiate: ToInstantiate = - val buf = new mutable.ListBuffer[(TypeVar, Int)] - for tvar <- qualifying do - if !tvar.isInstantiated && constraint.contains(tvar) && tvar.nestingLevel >= ctx.nestingLevel then - constrainIfDependentParamRef(tvar, tree) - if !tvar.isInstantiated then - // isInstantiated needs to be checked again, since previous interpolations could already have - // instantiated `tvar` through unification. - val v = vs.computedVariance(tvar) - if v == null then buf += ((tvar, 0)) - else if v.intValue != 0 then buf += ((tvar, v.intValue)) - else comparing(cmp => - if !cmp.levelOK(tvar.nestingLevel, ctx.nestingLevel) then - // Invariant: The type of a tree whose enclosing scope is level - // N only contains type variables of level <= N. - typr.println(i"instantiate nonvariant $tvar of level ${tvar.nestingLevel} to a type variable of level <= ${ctx.nestingLevel}, $constraint") - cmp.atLevel(ctx.nestingLevel, tvar.origin) - else - typr.println(i"no interpolation for nonvariant $tvar in $state") - ) - // constrainIfDependentParamRef could also have instantiated tvars added to buf before the check - buf.filterNot(_._1.isInstantiated).toList - end toInstantiate - - def typeVarsIn(xs: ToInstantiate): TypeVars = - xs.foldLeft(SimpleIdentitySet.empty: TypeVars)((tvs, tvi) => tvs + tvi._1) - - /** Filter list of proposed instantiations so that they don't constrain further - * the current constraint. - */ - def filterByDeps(tvs0: ToInstantiate): ToInstantiate = - val excluded = // ignore dependencies from other variables that are being instantiated - typeVarsIn(tvs0) - def step(tvs: ToInstantiate): ToInstantiate = tvs match - case tvs @ (hd @ (tvar, v)) :: tvs1 => - def aboveOK = !constraint.dependsOn(tvar, excluded, co = true) - def belowOK = !constraint.dependsOn(tvar, excluded, co = false) - if v == 0 && !aboveOK then - step((tvar, 1) :: tvs1) - else if v == 0 && !belowOK then - step((tvar, -1) :: tvs1) - else if v == -1 && !aboveOK || v == 1 && !belowOK then - typr.println(i"drop $tvar, $v in $tp, $pt, qualifying = ${qualifying.toList}, tvs0 = ${tvs0.toList}%, %, excluded = ${excluded.toList}, $constraint") - step(tvs1) - else // no conflict, keep the instantiation proposal - tvs.derivedCons(hd, step(tvs1)) - case Nil => - Nil - val tvs1 = step(tvs0) - if tvs1 eq tvs0 then tvs1 - else filterByDeps(tvs1) // filter again with smaller excluded set - end filterByDeps - - /** Instantiate all type variables in `tvs` in the indicated directions, - * as described in the doc comment of `ToInstantiate`. - * If a type variable A is instantiated from below, and there is another - * type variable B in `buf` that is known to be smaller than A, wait and - * instantiate all other type variables before trying to instantiate A again. - * Dually, wait instantiating a type variable from above as long as it has - * upper bounds in `buf`. - * - * This is done to avoid loss of precision when forming unions. An example - * is in i7558.scala: - * - * type Tr[+V1, +O1 <: V1] - * extension [V2, O2 <: V2](tr: Tr[V2, O2]) def sl: Tr[V2, O2] = ??? - * def as[V3, O3 <: V3](tr: Tr[V3, O3]) : Tr[V3, O3] = tr.sl - * - * Here we interpolate at some point V2 and O2 given the constraint - * - * V2 >: V3, O2 >: O3, O2 <: V2 - * - * where O3 and V3 are type refs with O3 <: V3. - * If we interpolate V2 first to V3 | O2, the widenUnion algorithm will - * instantiate O2 to V3, leading to the final constraint - * - * V2 := V3, O2 := V3 - * - * But if we instantiate O2 first to O3, and V2 next to V3, we get the - * more flexible instantiation - * - * V2 := V3, O2 := O3 - */ - def doInstantiate(tvs: ToInstantiate): Unit = - - /** Try to instantiate `tvs`, return any suspended type variables */ - def tryInstantiate(tvs: ToInstantiate): ToInstantiate = tvs match - case (hd @ (tvar, v)) :: tvs1 => - val fromBelow = v == 1 || (v == 0 && tvar.hasLowerBound) - typr.println( - i"interpolate${if v == 0 then " non-occurring" else ""} $tvar in $state in $tree: $tp, fromBelow = $fromBelow, $constraint") - if tvar.isInstantiated then - tryInstantiate(tvs1) - else - val suspend = tvs1.exists{ (following, _) => - if fromBelow - then constraint.isLess(following.origin, tvar.origin) - else constraint.isLess(tvar.origin, following.origin) - } - if suspend then - typr.println(i"suspended: $hd") - hd :: tryInstantiate(tvs1) - else - tvar.instantiate(fromBelow) - tryInstantiate(tvs1) - case Nil => Nil - if tvs.nonEmpty then doInstantiate(tryInstantiate(tvs)) - end doInstantiate - - doInstantiate(filterByDeps(toInstantiate)) - } + instantiateTypeVars(tp, pt, qualifying, tree) } end if tree end interpolateTypeVars + def instantiateTypeVars(tp: Type, pt: Type, qualifying: List[TypeVar], tree: Tree = EmptyTree)(using Context): Unit = + trace(i"instantiateTypeVars($tp, $pt, $qualifying, $tree)", typr): + val state = ctx.typerState + def constraint = state.constraint + + val vs = variances(tp, pt) + + /** Values of this type report type variables to instantiate with variance indication: + * +1 variable appears covariantly, can be instantiated from lower bound + * -1 variable appears contravariantly, can be instantiated from upper bound + * 0 variable does not appear at all, can be instantiated from either bound + */ + type ToInstantiate = List[(TypeVar, Int)] + + val toInstantiate: ToInstantiate = + val buf = new mutable.ListBuffer[(TypeVar, Int)] + for tvar <- qualifying do + if !tvar.isInstantiated && constraint.contains(tvar) && tvar.nestingLevel >= ctx.nestingLevel then + constrainIfDependentParamRef(tvar, tree) + if !tvar.isInstantiated then + // isInstantiated needs to be checked again, since previous interpolations could already have + // instantiated `tvar` through unification. + val v = vs.computedVariance(tvar) + if v == null then buf += ((tvar, 0)) + else if v.intValue != 0 then buf += ((tvar, v.intValue)) + else comparing(cmp => + if !cmp.levelOK(tvar.nestingLevel, ctx.nestingLevel) then + // Invariant: The type of a tree whose enclosing scope is level + // N only contains type variables of level <= N. + typr.println(i"instantiate nonvariant $tvar of level ${tvar.nestingLevel} to a type variable of level <= ${ctx.nestingLevel}, $constraint") + cmp.atLevel(ctx.nestingLevel, tvar.origin) + else + typr.println(i"no interpolation for nonvariant $tvar in $state") + ) + // constrainIfDependentParamRef could also have instantiated tvars added to buf before the check + buf.filterNot(_._1.isInstantiated).toList + end toInstantiate + + def typeVarsIn(xs: ToInstantiate): TypeVars = + xs.foldLeft(SimpleIdentitySet.empty: TypeVars)((tvs, tvi) => tvs + tvi._1) + + /** Filter list of proposed instantiations so that they don't constrain further + * the current constraint. + */ + def filterByDeps(tvs0: ToInstantiate): ToInstantiate = + val excluded = // ignore dependencies from other variables that are being instantiated + typeVarsIn(tvs0) + def step(tvs: ToInstantiate): ToInstantiate = tvs match + case tvs @ (hd @ (tvar, v)) :: tvs1 => + def aboveOK = !constraint.dependsOn(tvar, excluded, co = true) + def belowOK = !constraint.dependsOn(tvar, excluded, co = false) + if v == 0 && !aboveOK then + step((tvar, 1) :: tvs1) + else if v == 0 && !belowOK then + step((tvar, -1) :: tvs1) + else if v == -1 && !aboveOK || v == 1 && !belowOK then + typr.println(i"drop $tvar, $v in $tp, $pt, qualifying = ${qualifying.toList}, tvs0 = ${tvs0.toList}%, %, excluded = ${excluded.toList}, $constraint") + step(tvs1) + else // no conflict, keep the instantiation proposal + tvs.derivedCons(hd, step(tvs1)) + case Nil => + Nil + val tvs1 = step(tvs0) + if tvs1 eq tvs0 then tvs1 + else filterByDeps(tvs1) // filter again with smaller excluded set + end filterByDeps + + /** Instantiate all type variables in `tvs` in the indicated directions, + * as described in the doc comment of `ToInstantiate`. + * If a type variable A is instantiated from below, and there is another + * type variable B in `buf` that is known to be smaller than A, wait and + * instantiate all other type variables before trying to instantiate A again. + * Dually, wait instantiating a type variable from above as long as it has + * upper bounds in `buf`. + * + * This is done to avoid loss of precision when forming unions. An example + * is in i7558.scala: + * + * type Tr[+V1, +O1 <: V1] + * extension [V2, O2 <: V2](tr: Tr[V2, O2]) def sl: Tr[V2, O2] = ??? + * def as[V3, O3 <: V3](tr: Tr[V3, O3]) : Tr[V3, O3] = tr.sl + * + * Here we interpolate at some point V2 and O2 given the constraint + * + * V2 >: V3, O2 >: O3, O2 <: V2 + * + * where O3 and V3 are type refs with O3 <: V3. + * If we interpolate V2 first to V3 | O2, the widenUnion algorithm will + * instantiate O2 to V3, leading to the final constraint + * + * V2 := V3, O2 := V3 + * + * But if we instantiate O2 first to O3, and V2 next to V3, we get the + * more flexible instantiation + * + * V2 := V3, O2 := O3 + */ + def doInstantiate(tvs: ToInstantiate): Unit = + + /** Try to instantiate `tvs`, return any suspended type variables */ + def tryInstantiate(tvs: ToInstantiate): ToInstantiate = tvs match + case (hd @ (tvar, v)) :: tvs1 => + val fromBelow = v == 1 || (v == 0 && tvar.hasLowerBound) + typr.println( + i"interpolate${if v == 0 then " non-occurring" else ""} $tvar in $state in $tree: $tp, fromBelow = $fromBelow, $constraint") + if tvar.isInstantiated then + tryInstantiate(tvs1) + else + val suspend = tvs1.exists{ (following, _) => + if fromBelow + then constraint.isLess(following.origin, tvar.origin) + else constraint.isLess(tvar.origin, following.origin) + } + if suspend then + typr.println(i"suspended: $hd") + hd :: tryInstantiate(tvs1) + else + tvar.instantiate(fromBelow) + tryInstantiate(tvs1) + case Nil => Nil + if tvs.nonEmpty then doInstantiate(tryInstantiate(tvs)) + end doInstantiate + + doInstantiate(filterByDeps(toInstantiate)) + end instantiateTypeVars + /** If `tvar` represents a parameter of a dependent method type in the current `call` * approximate it from below with the type of the actual argument. Skolemize that * type if necessary to make it a Singleton. diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index 9694822bc0d5..89a2cbbfbc21 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -69,13 +69,6 @@ object ProtoTypes { |constraint was: ${ctx.typerState.constraint} |constraint now: ${newctx.typerState.constraint}""") if result && (ctx.typerState.constraint ne newctx.typerState.constraint) then - // Remove all type lambdas and tvars introduced by testCompat - for tvar <- newctx.typerState.ownedVars do - inContext(newctx): - if !tvar.isInstantiated then - tvar.instantiate(fromBelow = false) // any direction - - // commit any remaining changes in typer state newctx.typerState.commit() result case _ => testCompat diff --git a/tests/pos/i21981.alt.scala b/tests/pos/i21981.alt.scala new file mode 100644 index 000000000000..0662575757a8 --- /dev/null +++ b/tests/pos/i21981.alt.scala @@ -0,0 +1,24 @@ +trait Ops[F[_], A]: + def map0[B](f0: A => B): F[B] = ??? + +trait Functor1[G[_]] + +trait Functor2[H[_]] + +trait Ref[I[_], +E] + +class Test: + given [J[_]](using J: Functor1[J]): Functor2[J] with + extension [K1, K2](jk: J[(K1, K2)]) + def map2[L](f2: (K1, K2) => L): J[L] = ??? + + def t1[ + M[_[t]], + N[_], + ](using N: Functor1[N]): Unit = + + val x3: Ops[N, M[[t] =>> Ref[N, t]]] = ??? + + val x2: N[(M[N], M[[t] =>> Ref[N, t]])] = x3 + .map0 { refs => (???, refs) } + .map2 { case (not, refs) => (???, refs) } diff --git a/tests/pos/i21981.contrak.scala b/tests/pos/i21981.contrak.scala new file mode 100644 index 000000000000..6ce64e6d3ddf --- /dev/null +++ b/tests/pos/i21981.contrak.scala @@ -0,0 +1,27 @@ +case class Inv[T](x: T) +class Contra[-ContraParam](x: ContraParam) + +trait Ops[F[_], A]: + def map0[B](f0: A => Contra[B]): F[B] = ??? + +trait Functor1[G[_]] + +trait Functor2[H[_]] + +trait Ref[I[_], +E] + +class Test: + given [J[_]](using J: Functor1[J]): Functor2[J] with + extension [K](jk: J[Contra[K]]) + def map2[L](f2: K => L): J[L] = ??? + + def t1[ + M[_[t]], + N[_], + ](using N: Functor1[N]): Unit = + + val x3: Ops[N, M[[t] =>> Ref[N, t]]] = ??? + + val x2: N[(M[N], M[[t] =>> Ref[N, t]])] = x3 + .map0 { refs => Contra[Contra[(Nothing, M[[t] =>> Ref[N, t]])]](???) } + .map2 { case (not, refs) => (???, refs) } diff --git a/tests/pos/i21981.orig.scala b/tests/pos/i21981.orig.scala new file mode 100644 index 000000000000..c02eb4848649 --- /dev/null +++ b/tests/pos/i21981.orig.scala @@ -0,0 +1,29 @@ +object internal: + trait Functor[F[_]] { + extension [T](ft: F[T]) def map[T1](f: T => T1): F[T1] + } + +object cats: + trait Functor[F[_]] + object Functor: + trait Ops[F[_], A]: + def map[B](f: A => B): F[B] = ??? + def toAllFunctorOps[F[_], A](target: F[A])(using Functor[F]): Ops[F, A] = ??? + +given [F[_]](using cf: cats.Functor[F]): internal.Functor[F] with { + extension [T](ft: F[T]) def map[T1](f: T => T1): F[T1] = ??? +} + +trait Ref[F[_], +T] +class MemoizingEvaluator[Input[_[_]], Output[_[_]], F[_]: cats.Functor] { + type OptionRef[T] = Ref[F, Option[T]] + + def sequence[CaseClass[_[_]], G[_], H[_]](instance: CaseClass[[t] =>> G[H[t]]]): G[CaseClass[H]] = ??? + def collectValues(input: Input[F]): F[(Input[F], Input[OptionRef])] = { + val refsF: Input[[t] =>> F[OptionRef[t]]] = ??? + for { + refs <- cats.Functor.toAllFunctorOps(sequence[Input, F, OptionRef](refsF)) + updating = ??? + } yield (updating, refs) + } +} diff --git a/tests/pos/i21981.scala b/tests/pos/i21981.scala new file mode 100644 index 000000000000..62962c7f1c56 --- /dev/null +++ b/tests/pos/i21981.scala @@ -0,0 +1,24 @@ +trait Ops[F[_], A]: + def map0[B](f0: A => B): F[B] = ??? + +trait Functor1[G[_]] + +trait Functor2[H[_]] + +trait Ref[I[_], +E] + +class Test: + given [J[_]](using J: Functor1[J]): Functor2[J] with + extension [K](jk: J[K]) + def map2[L](f2: K => L): J[L] = ??? + + def t1[ + M[_[t]], + N[_], + ](using N: Functor1[N]): Unit = + + val x3: Ops[N, M[[t] =>> Ref[N, t]]] = ??? + + val x2: N[(M[N], M[[t] =>> Ref[N, t]])] = x3 + .map0 { refs => (???, refs) } + .map2 { case (not, refs) => (???, refs) } From 8b1007358fb9bfac1a4e2c60f5f2f3b84045ad82 Mon Sep 17 00:00:00 2001 From: Jan Chyb <48855024+jchyb@users.noreply.github.com> Date: Tue, 4 Mar 2025 19:19:28 +0100 Subject: [PATCH 149/505] Try not to approximate prefixes when using memberType in reflect API (#22448) To achieve this, we substitute This types in `member.info` referencing classSymbol with TypeReprs actual self (which may or may not be a This type) Fixes #22424 --- .../quoted/runtime/impl/QuotesImpl.scala | 10 +++++++- tests/pos-macros/i22424/Macro_1.scala | 25 +++++++++++++++++++ tests/pos-macros/i22424/Test_2.scala | 4 +++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tests/pos-macros/i22424/Macro_1.scala create mode 100644 tests/pos-macros/i22424/Test_2.scala diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index a1673f017cd7..172b3a35aabb 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -1795,7 +1795,15 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler def termSymbol: Symbol = self.termSymbol def isSingleton: Boolean = self.isSingleton def memberType(member: Symbol): TypeRepr = - member.info.asSeenFrom(self, member.owner) + // we replace thisTypes here to avoid resolving otherwise unstable prefixes into Nothing + val memberInfo = + if self.typeSymbol.isClassDef then + member.info.substThis(self.classSymbol.asClass, self) + else + member.info + memberInfo + .asSeenFrom(self, member.owner) + def baseClasses: List[Symbol] = self.baseClasses def baseType(cls: Symbol): TypeRepr = self.baseType(cls) def derivesFrom(cls: Symbol): Boolean = self.derivesFrom(cls) diff --git a/tests/pos-macros/i22424/Macro_1.scala b/tests/pos-macros/i22424/Macro_1.scala new file mode 100644 index 000000000000..634cfb0055c7 --- /dev/null +++ b/tests/pos-macros/i22424/Macro_1.scala @@ -0,0 +1,25 @@ + +import scala.quoted.* + +object MockMaker: + inline def inlineMock[T]: Unit = ${instance[T]} + transparent inline def transparentInlineMock[T]: Unit = ${instance[T]} + + def instance[T: Type](using quotes: Quotes): Expr[Unit] = + import quotes.reflect._ + val tpe = TypeRepr.of[T] + val symbol = tpe.typeSymbol.methodMember("innerTraitInOptions").head + tpe.memberType(symbol) match + case mt @ MethodType(_, args, _) => + assert(args.head.typeSymbol != TypeRepr.of[Nothing].typeSymbol, "argument is incorrectly approximated") + val shownType = mt.show + val expectedType = "(x: m.Embedded#ATrait[scala.Predef.String, scala.Int])m.Embedded#ATrait[scala.Predef.String, scala.Int]" + assert(shownType == expectedType, s"Incorrect type shown. Obtained: $shownType, Expected: $expectedType") + '{()} + +trait PolymorphicTrait { + trait Embedded { + trait ATrait[A, B] + def innerTraitInOptions(x: ATrait[String, Int]): ATrait[String, Int] + } +} diff --git a/tests/pos-macros/i22424/Test_2.scala b/tests/pos-macros/i22424/Test_2.scala new file mode 100644 index 000000000000..0a231d820381 --- /dev/null +++ b/tests/pos-macros/i22424/Test_2.scala @@ -0,0 +1,4 @@ +@main def Test = + val m = new PolymorphicTrait {} + MockMaker.inlineMock[m.Embedded] + MockMaker.transparentInlineMock[m.Embedded] From 1cdc3cc4a8a7f1780974c725bf60a8a67be75654 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Wed, 23 Apr 2025 18:01:37 +0200 Subject: [PATCH 150/505] Try not to approximate prefixes when using memberType in reflect API (#22448) To achieve this, we substitute This types in `member.info` referencing classSymbol with TypeReprs actual self (which may or may not be a This type) Fixes #22424 [Cherry-picked 26857506efef28e108a2c8d0a6c4ea766b47b033][modified] From 0c57f8e8da5d5216866233f6acc2504dc55ea023 Mon Sep 17 00:00:00 2001 From: Daisy Li Date: Sun, 9 Feb 2025 11:34:45 -0500 Subject: [PATCH 151/505] Add error-checking when fetching rhs of ValOrDefDefs. --- .../tools/dotc/transform/init/Semantic.scala | 49 ++++++++++++++----- .../dotty/tools/dotc/CompilationTests.scala | 23 +++++++++ tests/init/tasty-error/Main.scala | 1 + tests/init/tasty-error/v0/A.scala | 3 ++ tests/init/tasty-error/v1/A.scala | 3 ++ tests/init/tasty-error/v1/B.scala | 4 ++ 6 files changed, 70 insertions(+), 13 deletions(-) create mode 100644 tests/init/tasty-error/Main.scala create mode 100644 tests/init/tasty-error/v0/A.scala create mode 100644 tests/init/tasty-error/v1/A.scala create mode 100644 tests/init/tasty-error/v1/B.scala diff --git a/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala b/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala index 4548dccb598f..5d9b4f0e5ce0 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala @@ -378,7 +378,7 @@ object Semantic: // ----- Checker State ----------------------------------- /** The state that threads through the interpreter */ - type Contextual[T] = (Context, Trace, Promoted, Cache.Data, Reporter) ?=> T + type Contextual[T] = (Context, Trace, Promoted, Cache.Data, Reporter, TreeCache.CacheData) ?=> T // ----- Error Handling ----------------------------------- @@ -443,6 +443,29 @@ object Semantic: inline def reporter(using r: Reporter): Reporter = r +// ----- Cache for Trees ----------------------------- + + object TreeCache: + class CacheData: + private val emptyTrees = mutable.Set[ValOrDefDef]() + + extension (tree: ValOrDefDef) + def getRhs(using Context): Tree = + def getTree: Tree = + val errorCount = ctx.reporter.errorCount + val rhs = tree.rhs + + if (ctx.reporter.errorCount > errorCount) + emptyTrees.add(tree) + report.warning("Ignoring analyses of " + tree.name + " due to error in reading TASTy.") + EmptyTree + else + rhs + + if (emptyTrees.contains(tree)) EmptyTree + else getTree + end TreeCache + // ----- Operations on domains ----------------------------- extension (a: Value) def join(b: Value): Value = @@ -562,7 +585,7 @@ object Semantic: case ref: Ref => val target = if needResolve then resolve(ref.klass, field) else field if target.is(Flags.Lazy) then - val rhs = target.defTree.asInstanceOf[ValDef].rhs + val rhs = target.defTree.asInstanceOf[ValDef].getRhs eval(rhs, ref, target.owner.asClass, cacheResult = true) else if target.exists then val obj = ref.objekt @@ -577,7 +600,7 @@ object Semantic: // return `Hot` here, errors are reported in checking `ThisRef` Hot else if target.hasSource then - val rhs = target.defTree.asInstanceOf[ValOrDefDef].rhs + val rhs = target.defTree.asInstanceOf[ValOrDefDef].getRhs eval(rhs, ref, target.owner.asClass, cacheResult = true) else val error = CallUnknown(field)(trace) @@ -701,7 +724,7 @@ object Semantic: else reporter.reportAll(tryReporter.errors) extendTrace(ddef) { - eval(ddef.rhs, ref, cls, cacheResult = true) + eval(ddef.getRhs, ref, cls, cacheResult = true) } else if ref.canIgnoreMethodCall(target) then Hot @@ -768,7 +791,7 @@ object Semantic: val tpl = cls.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template] extendTrace(cls.defTree) { init(tpl, ref, cls) } else - val initCall = ddef.rhs match + val initCall = ddef.getRhs match case Block(call :: _, _) => call case call => call extendTrace(ddef) { eval(initCall, ref, cls) } @@ -787,7 +810,7 @@ object Semantic: extendTrace(cls.defTree) { eval(tpl, ref, cls, cacheResult = true) } ref else - extendTrace(ddef) { eval(ddef.rhs, ref, cls, cacheResult = true) } + extendTrace(ddef) { eval(ddef.getRhs, ref, cls, cacheResult = true) } else if ref.canIgnoreMethodCall(ctor) then Hot else @@ -897,8 +920,7 @@ object Semantic: case Cold => Cold - case ref: Ref => eval(vdef.rhs, ref, enclosingClass, cacheResult = sym.is(Flags.Lazy)) - + case ref: Ref => eval(vdef.getRhs, ref, enclosingClass, cacheResult = sym.is(Flags.Lazy)) case _ => report.error("[Internal error] unexpected this value when accessing local variable, sym = " + sym.show + ", thisValue = " + thisValue2.show + Trace.show, Trace.position) Hot @@ -1105,7 +1127,7 @@ object Semantic: * * The class to be checked must be an instantiable concrete class. */ - private def checkClass(classSym: ClassSymbol)(using Cache.Data, Context): Unit = + private def checkClass(classSym: ClassSymbol)(using Cache.Data, Context, TreeCache.CacheData): Unit = val thisRef = ThisRef(classSym) val tpl = classSym.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template] @@ -1140,6 +1162,7 @@ object Semantic: */ def checkClasses(classes: List[ClassSymbol])(using Context): Unit = given Cache.Data() + given TreeCache.CacheData() for classSym <- classes if isConcreteClass(classSym) do checkClass(classSym) @@ -1298,7 +1321,7 @@ object Semantic: } case closureDef(ddef) => - Fun(ddef.rhs, thisV, klass) + Fun(ddef.getRhs, thisV, klass) case PolyFun(body) => Fun(body, thisV, klass) @@ -1353,7 +1376,7 @@ object Semantic: case vdef : ValDef => // local val definition - eval(vdef.rhs, thisV, klass) + eval(vdef.getRhs, thisV, klass) case ddef : DefDef => // local method @@ -1571,8 +1594,8 @@ object Semantic: // class body if thisV.isThisRef || !thisV.asInstanceOf[Warm].isPopulatingParams then tpl.body.foreach { - case vdef : ValDef if !vdef.symbol.is(Flags.Lazy) && !vdef.rhs.isEmpty => - val res = eval(vdef.rhs, thisV, klass) + case vdef : ValDef if !vdef.symbol.is(Flags.Lazy) && !vdef.getRhs.isEmpty => + val res = eval(vdef.getRhs, thisV, klass) // TODO: Improve promotion to avoid handling enum initialization specially // // The failing case is tests/init/pos/i12544.scala due to promotion failure. diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index 1b33c52416ea..e9562b016a74 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -235,6 +235,29 @@ class CompilationTests { tests.foreach(_.delete()) } + + /* This tests for errors in the program's TASTy trees. + * The test consists of three files: (a) v1/A, (b) v1/B, and (c) v0/A. (a) and (b) are + * compatible, but (b) and (c) are not. If (b) and (c) are compiled together, there should be + * an error when reading the files' TASTy trees. */ + locally { + val tastyErrorGroup = TestGroup("checkInit/tasty-error") + val tastyErrorOptions = options.without("-Xfatal-warnings") + + val a0Dir = defaultOutputDir + tastyErrorGroup + "/A/v0/A" + val a1Dir = defaultOutputDir + tastyErrorGroup + "/A/v1/A" + val b1Dir = defaultOutputDir + tastyErrorGroup + "/B/v1/B" + + val tests = List( + compileFile("tests/init/tasty-error/v1/A.scala", tastyErrorOptions)(tastyErrorGroup), + compileFile("tests/init/tasty-error/v1/B.scala", tastyErrorOptions.withClasspath(a1Dir))(tastyErrorGroup), + compileFile("tests/init/tasty-error/v0/A.scala", tastyErrorOptions)(tastyErrorGroup), + ).map(_.keepOutput.checkCompile()) + + compileFile("tests/init/tasty-error/Main.scala", tastyErrorOptions.withClasspath(a0Dir).withClasspath(b1Dir))(tastyErrorGroup).checkExpectedErrors() + + tests.foreach(_.delete()) + } } // parallel backend tests diff --git a/tests/init/tasty-error/Main.scala b/tests/init/tasty-error/Main.scala new file mode 100644 index 000000000000..2b27dd2b0d1f --- /dev/null +++ b/tests/init/tasty-error/Main.scala @@ -0,0 +1 @@ +class Main extends B{} // anypos-error \ No newline at end of file diff --git a/tests/init/tasty-error/v0/A.scala b/tests/init/tasty-error/v0/A.scala new file mode 100644 index 000000000000..be8c7d214378 --- /dev/null +++ b/tests/init/tasty-error/v0/A.scala @@ -0,0 +1,3 @@ +class A { + def fail(a: Int, b: Int): Int = a +} \ No newline at end of file diff --git a/tests/init/tasty-error/v1/A.scala b/tests/init/tasty-error/v1/A.scala new file mode 100644 index 000000000000..fa2956d1de7e --- /dev/null +++ b/tests/init/tasty-error/v1/A.scala @@ -0,0 +1,3 @@ +class A { + def fail(a: Int): Int = a +} \ No newline at end of file diff --git a/tests/init/tasty-error/v1/B.scala b/tests/init/tasty-error/v1/B.scala new file mode 100644 index 000000000000..3059f487db64 --- /dev/null +++ b/tests/init/tasty-error/v1/B.scala @@ -0,0 +1,4 @@ +class B { + val a: A = new A + val x = a.fail(0) +} \ No newline at end of file From 074e40ea0571a7e6cb25c0efae07c57b4e1d9e6c Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Wed, 23 Apr 2025 18:03:44 +0200 Subject: [PATCH 152/505] Add error-checking when fetching rhs of ValOrDefDefs. [Cherry-picked e80888176d5645b3c26075423e93454dc766b8e1][modified] From ba16067f6276ce8103cb1e9de4c1e00bb0fb21dc Mon Sep 17 00:00:00 2001 From: Jan Chyb Date: Wed, 5 Mar 2025 12:12:13 +0100 Subject: [PATCH 153/505] Make sure TypeBlocks are not incorrectly matched against Blocks [Cherry-picked 71044a8882fd9bd13d5b27834aa79f4096650318] --- .../src/scala/quoted/runtime/impl/QuotesImpl.scala | 2 +- tests/{pos/i21721 => pos-macros/i21721-a}/Macro.scala | 0 tests/{pos/i21721 => pos-macros/i21721-a}/Test.scala | 0 tests/pos-macros/i21721-b/Macro_1.scala | 11 +++++++++++ tests/pos-macros/i21721-b/Test_2.scala | 1 + 5 files changed, 13 insertions(+), 1 deletion(-) rename tests/{pos/i21721 => pos-macros/i21721-a}/Macro.scala (100%) rename tests/{pos/i21721 => pos-macros/i21721-a}/Test.scala (100%) create mode 100644 tests/pos-macros/i21721-b/Macro_1.scala create mode 100644 tests/pos-macros/i21721-b/Test_2.scala diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index 172b3a35aabb..a666feace741 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -805,7 +805,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler object BlockTypeTest extends TypeTest[Tree, Block]: def unapply(x: Tree): Option[Block & x.type] = x match - case x: (tpd.Block & x.type) => Some(x) + case x: (tpd.Block & x.type) if x.isTerm => Some(x) case _ => None end BlockTypeTest diff --git a/tests/pos/i21721/Macro.scala b/tests/pos-macros/i21721-a/Macro.scala similarity index 100% rename from tests/pos/i21721/Macro.scala rename to tests/pos-macros/i21721-a/Macro.scala diff --git a/tests/pos/i21721/Test.scala b/tests/pos-macros/i21721-a/Test.scala similarity index 100% rename from tests/pos/i21721/Test.scala rename to tests/pos-macros/i21721-a/Test.scala diff --git a/tests/pos-macros/i21721-b/Macro_1.scala b/tests/pos-macros/i21721-b/Macro_1.scala new file mode 100644 index 000000000000..aad7d6232c8f --- /dev/null +++ b/tests/pos-macros/i21721-b/Macro_1.scala @@ -0,0 +1,11 @@ +import scala.quoted._ + +inline def test(): Any = ${ testImpl } + +def testImpl(using Quotes): Expr[Any] = + import quotes.reflect._ + TypeBlock(Nil, TypeTree.of[Int]) match + case Block(_, res) => + res.asExpr // unexpected case - would crash here, as res of TypeBlock is not a term + case _ => + '{()} // expected case diff --git a/tests/pos-macros/i21721-b/Test_2.scala b/tests/pos-macros/i21721-b/Test_2.scala new file mode 100644 index 000000000000..9b75f0ca5777 --- /dev/null +++ b/tests/pos-macros/i21721-b/Test_2.scala @@ -0,0 +1 @@ +@main def Test() = test() From ddea9bbf7e79e6481da9a57206644d051e94fca5 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Mon, 24 Feb 2025 20:05:46 -0800 Subject: [PATCH 154/505] Nowarn non-private implicit val class params Dowarn protected param accessor of given, which was probably widened. [Cherry-picked 2cb2c9252b68abc66936705fa1496f736d338dbe] --- tests/warn/i15503f.scala | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/warn/i15503f.scala b/tests/warn/i15503f.scala index 9d464bbc1973..79ee0a1767d4 100644 --- a/tests/warn/i15503f.scala +++ b/tests/warn/i15503f.scala @@ -43,3 +43,35 @@ object Unmatched: case Ident(name) => case _ => e + +trait Ctx +case class K(i: Int)(using val ctx: Ctx) // nowarn +class L(val i: Int)(using val ctx: Ctx) // nowarn +class M(val i: Int)(using ctx: Ctx) // warn + +package givens: + + trait X: + def doX: Int + + trait Y: + def doY: String + + given X: + def doX = 7 + + given X => Y: // warn protected param to given class + def doY = "7" + /* desugared. It is protected so that its type can be used in member defs without leaking. + * possibly it should be protected only for named parameters. + given class given_Y(using x$1: givens.X) extends Object(), givens.Y { + protected given val x$1: givens.X + def doY: String = "7" + } + final given def given_Y(using x$1: givens.X): givens.given_Y = + new givens.given_Y(using x$1)() + */ + + given namely: (x: X) => Y: // warn protected param to given class + def doY = "8" +end givens From 05fb7bc17163f0b861add6193da64a0ffdb995d3 Mon Sep 17 00:00:00 2001 From: Seth Tisue Date: Thu, 27 Feb 2025 17:34:40 -0800 Subject: [PATCH 155/505] JLine 3.29.0 (was 3.27.1) [Cherry-picked 064c3df24709e57b367122af7d5c8841cd62a691] --- project/Build.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/project/Build.scala b/project/Build.scala index 2da2345e28fd..a63df060a841 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -666,9 +666,9 @@ object Build { libraryDependencies ++= Seq( "org.scala-lang.modules" % "scala-asm" % "9.7.1-scala-1", // used by the backend Dependencies.compilerInterface, - "org.jline" % "jline-reader" % "3.27.1", // used by the REPL - "org.jline" % "jline-terminal" % "3.27.1", - "org.jline" % "jline-terminal-jni" % "3.27.1", // needed for Windows + "org.jline" % "jline-reader" % "3.29.0", // used by the REPL + "org.jline" % "jline-terminal" % "3.29.0", + "org.jline" % "jline-terminal-jni" % "3.29.0", // needed for Windows ("io.get-coursier" %% "coursier" % "2.0.16" % Test).cross(CrossVersion.for3Use2_13), ), From 86169a85b6ed891eb2bb6376d7bcfeb57a71a24d Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Tue, 4 Mar 2025 17:48:20 -0800 Subject: [PATCH 156/505] Rename on import is never wildcard [Cherry-picked 977232cf3d919ccb6bf7c3fb93eda4b9241dac53] --- compiler/src/dotty/tools/dotc/transform/CheckUnused.scala | 5 ++++- tests/warn/i15503a.scala | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index 22d27cb61c66..a0ad1abb9724 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -275,8 +275,11 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha case sel :: sels => val matches = if sel.isWildcard then + // if name is different from sym.name, it must be a rename on import, not a wildcard selector + !name.exists(_.toTermName != sym.name.toTermName) // the qualifier must have the target symbol as a member - hasAltMember(sym.name) && { + && hasAltMember(sym.name) + && { if sel.isGiven then // Further check that the symbol is a given or implicit and conforms to the bound sym.isOneOf(GivenOrImplicit) && (sel.bound.isEmpty || sym.info.finalResultType <:< sel.boundTpe) diff --git a/tests/warn/i15503a.scala b/tests/warn/i15503a.scala index 40b6c75983bf..3707b18d316e 100644 --- a/tests/warn/i15503a.scala +++ b/tests/warn/i15503a.scala @@ -321,3 +321,10 @@ object Suppressed: object Suppressing: import Suppressed.* // no warn, see options def f = 42 + +package i22692: + import javax.swing.* + import javax.swing.event as swingEvent // no warn, regression test for warning in 3.6 + + type b = AbstractButton + type t = swingEvent.AncestorListener From fdf7cdc254edf3408a8d910ab8f7150aad04072d Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Wed, 23 Apr 2025 18:27:24 +0200 Subject: [PATCH 157/505] bugfix: Adjust givens to old syntax --- tests/warn/i15503f.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/warn/i15503f.scala b/tests/warn/i15503f.scala index 79ee0a1767d4..76badc659fb9 100644 --- a/tests/warn/i15503f.scala +++ b/tests/warn/i15503f.scala @@ -57,10 +57,10 @@ package givens: trait Y: def doY: String - given X: + given X with def doX = 7 - given X => Y: // warn protected param to given class + given (using X): Y with // warn protected param to given class def doY = "7" /* desugared. It is protected so that its type can be used in member defs without leaking. * possibly it should be protected only for named parameters. @@ -72,6 +72,6 @@ package givens: new givens.given_Y(using x$1)() */ - given namely: (x: X) => Y: // warn protected param to given class + given namely (using x: X): Y with // warn protected param to given class def doY = "8" end givens From 0cdd9767101cc995d0ef513ec4a6d06e22f19b12 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Sat, 8 Mar 2025 01:34:28 -0800 Subject: [PATCH 158/505] First cut at nowarn refinement members --- .../tools/dotc/transform/CheckUnused.scala | 22 +- tests/semanticdb/metac.expect | 244 +++++++++--------- tests/warn/i22681.scala | 17 ++ 3 files changed, 162 insertions(+), 121 deletions(-) create mode 100644 tests/warn/i22681.scala diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index a0ad1abb9724..bb298b1bcc16 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -150,6 +150,9 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha override def prepareForValDef(tree: ValDef)(using Context): Context = if !tree.symbol.is(Deferred) && tree.rhs.symbol != defn.Predef_undefined then refInfos.register(tree) + tree.tpt match + case RefinedTypeTree(_, refinements) => relax(tree.rhs, refinements) + case _ => ctx override def transformValDef(tree: ValDef)(using Context): tree.type = traverseAnnotations(tree.symbol) @@ -168,11 +171,15 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha override def prepareForDefDef(tree: DefDef)(using Context): Context = def trivial = tree.symbol.is(Deferred) || isUnconsuming(tree.rhs) def nontrivial = tree.symbol.isConstructor || tree.symbol.isAnonymousFunction - if !nontrivial && trivial then refInfos.skip.addOne(tree.symbol) + if !nontrivial && trivial then + refInfos.skip.addOne(tree.symbol) if tree.symbol.is(Inline) then refInfos.inliners += 1 else if !tree.symbol.is(Deferred) && tree.rhs.symbol != defn.Predef_undefined then refInfos.register(tree) + tree.tpt match + case RefinedTypeTree(_, refinements) => relax(tree.rhs, refinements) + case _ => ctx override def transformDefDef(tree: DefDef)(using Context): tree.type = traverseAnnotations(tree.symbol) @@ -447,7 +454,7 @@ object CheckUnused: if !tree.name.isInstanceOf[DerivedName] then pats.addOne((tree.symbol, tree.namePos)) case tree: NamedDefTree => - if (tree.symbol ne NoSymbol) && !tree.name.isWildcard then + if (tree.symbol ne NoSymbol) && !tree.name.isWildcard && !tree.hasAttachment(NoWarn) then defs.addOne((tree.symbol, tree.namePos)) case _ => if tree.symbol ne NoSymbol then @@ -843,6 +850,17 @@ object CheckUnused: args.foreach(traverse) case tree => traverseChildren(tree) + // NoWarn members in tree that correspond to refinements; currently uses only names. + def relax(tree: Tree, refinements: List[Tree])(using Context): Unit = + val names = refinements.collect { case named: NamedDefTree => named.name }.toSet + val relaxer = new TreeTraverser: + def traverse(tree: Tree)(using Context) = + tree match + case tree: NamedDefTree if names(tree.name) => tree.withAttachment(NoWarn, ()) + case _ => + traverseChildren(tree) + relaxer.traverse(tree) + extension (nm: Name) inline def exists(p: Name => Boolean): Boolean = nm.ne(nme.NO_NAME) && p(nm) inline def isWildcard: Boolean = nm == nme.WILDCARD || nm.is(WildcardParamName) diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index 4e3dee9d79a6..4ea5386b4c50 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -56,23 +56,23 @@ Synthetics => 3 entries Symbols: advanced/C# => class C [typeparam T ] extends Object { self: C[T] => +3 decls } -advanced/C#[T] => typeparam T +advanced/C#[T] => typeparam T advanced/C#``(). => primary ctor [typeparam T ](): C[T] advanced/C#t(). => method t => T advanced/HKClass# => class HKClass [typeparam F [typeparam T ] <: [U] =>> Tuple2[U, T]] extends Object { self: HKClass[F] => +3 decls } advanced/HKClass#[F] => typeparam F [typeparam T ] <: [U] =>> Tuple2[U, T] -advanced/HKClass#[F][T] => typeparam T -advanced/HKClass#[F][U] => typeparam U +advanced/HKClass#[F][T] => typeparam T +advanced/HKClass#[F][U] => typeparam U advanced/HKClass#``(). => primary ctor [typeparam F [typeparam T ] <: [U] =>> Tuple2[U, T]](): HKClass[F] -advanced/HKClass#``().[F][T] => typeparam T -advanced/HKClass#``().[F][U] => typeparam U +advanced/HKClass#``().[F][T] => typeparam T +advanced/HKClass#``().[F][U] => typeparam U advanced/HKClass#foo(). => method foo [typeparam T , typeparam U ](param x: F[T, U]): String advanced/HKClass#foo().(x) => param x: F[T, U] -advanced/HKClass#foo().[T] => typeparam T -advanced/HKClass#foo().[U] => typeparam U +advanced/HKClass#foo().[T] => typeparam T +advanced/HKClass#foo().[U] => typeparam U advanced/Structural# => class Structural extends Object { self: Structural => +6 decls } advanced/Structural#T# => trait T [typeparam A ] extends Object { self: T[A] => +4 decls } -advanced/Structural#T#[A] => typeparam A +advanced/Structural#T#[A] => typeparam A advanced/Structural#T#``(). => primary ctor [typeparam A ](): T[A] advanced/Structural#T#bar(). => method bar (param b: foo.B): Unit advanced/Structural#T#bar().(b) => param b: foo.B @@ -286,8 +286,8 @@ Symbols: annot/Alias. => final object Alias extends Object { self: Alias.type => +2 decls } annot/Alias.A# => type A = ClassAnnotation @param annot/Annotations# => @ClassAnnotation class Annotations [@TypeParameterAnnotation typeparam T ] extends Object { self: AnyRef & Annotations[T] => +6 decls } -annot/Annotations#S# => @TypeAnnotation type S -annot/Annotations#[T] => @TypeParameterAnnotation typeparam T +annot/Annotations#S# => @TypeAnnotation type S +annot/Annotations#[T] => @TypeParameterAnnotation typeparam T annot/Annotations#``(). => primary ctor [@TypeParameterAnnotation typeparam T ](@ParameterAnnotation param x: T): Annotations[T] annot/Annotations#``().(x) => @ParameterAnnotation param x: T annot/Annotations#field. => @FieldAnnotation val method field Int @@ -301,7 +301,7 @@ annot/B#throwing(). => @throws[Exception] method throwing => Nothing annot/B#x. => private[this] val method x Int annot/M. => @ObjectAnnotation final object M extends Object { self: M.type => +1 decls } annot/M.m(). => @MacroAnnotation macro m [typeparam TT ]: Int -annot/M.m().[TT] => typeparam TT +annot/M.m().[TT] => typeparam TT annot/T# => @TraitAnnotation trait T extends Object { self: T => +1 decls } annot/T#``(). => primary ctor (): T local0 => selfparam self: AnyRef @@ -394,10 +394,10 @@ example/Anonymous#bar2. => val method bar2 Bar example/Anonymous#foo. => val method foo Foo example/Anonymous#locally(). => method locally [typeparam A ](param x: A): A example/Anonymous#locally().(x) => param x: A -example/Anonymous#locally().[A] => typeparam A +example/Anonymous#locally().[A] => typeparam A example/Anonymous#m1(). => method m1 [typeparam T [type _ ]]: Nothing example/Anonymous#m1().[T] => typeparam T [type _ ] -example/Anonymous#m1().[T][_] => type _ +example/Anonymous#m1().[T][_] => type _ example/Anonymous#m2(). => method m2 => Map[_, List[_] forSome { type _ }] forSome { type _ } local0 => val local x: Function1[Int, Int] local1 => final class $anon extends Object with Foo { self: $anon => +1 decls } @@ -632,7 +632,7 @@ classes/C11#foo(). => inline macro foo => Int classes/C12# => class C12 extends Object { self: C12 => +8 decls } classes/C12#Context# => class Context extends Object { self: Context => +2 decls } classes/C12#Context#Expr# => type Expr [typeparam T ] -classes/C12#Context#Expr#[T] => typeparam T +classes/C12#Context#Expr#[T] => typeparam T classes/C12#Context#``(). => primary ctor (): Context classes/C12#``(). => primary ctor (): C12 classes/C12#foo1(). => macro foo1 (param x: Int): Int @@ -923,7 +923,7 @@ endmarkers/MultiCtor#``().(i) => val param i: Int endmarkers/MultiCtor#``(+1). => ctor (): MultiCtor endmarkers/MultiCtor#i. => val method i Int endmarkers/Stuff# => trait Stuff [typeparam A ] extends Object { self: Stuff[A] => +3 decls } -endmarkers/Stuff#[A] => typeparam A +endmarkers/Stuff#[A] => typeparam A endmarkers/Stuff#``(). => primary ctor [typeparam A ](): Stuff[A] endmarkers/Stuff#do(). => abstract method do => A endmarkers/TestObj. => final object TestObj extends Object { self: TestObj.type => +2 decls } @@ -1122,29 +1122,29 @@ _empty_/Enums.Directions.valueOf(). => method valueOf (param $name: String): Dir _empty_/Enums.Directions.valueOf().($name) => param $name: String _empty_/Enums.Directions.values(). => method values => Array[Directions] _empty_/Enums.Maybe# => abstract sealed enum class Maybe [covariant typeparam A ] extends Object with Enum { self: Maybe[A] => +2 decls } -_empty_/Enums.Maybe#[A] => covariant typeparam A +_empty_/Enums.Maybe#[A] => covariant typeparam A _empty_/Enums.Maybe#``(). => primary ctor [covariant typeparam A ](): Maybe[A] _empty_/Enums.Maybe. => final object Maybe extends Object { self: Maybe.type => +6 decls } _empty_/Enums.Maybe.Just# => final case enum class Just [covariant typeparam A ] extends Maybe[A] { self: Just[A] => +7 decls } -_empty_/Enums.Maybe.Just#[A] => covariant typeparam A +_empty_/Enums.Maybe.Just#[A] => covariant typeparam A _empty_/Enums.Maybe.Just#_1(). => method _1 => A _empty_/Enums.Maybe.Just#``(). => primary ctor [covariant typeparam A ](val param value: A): Just[A] _empty_/Enums.Maybe.Just#``().(value) => val param value: A _empty_/Enums.Maybe.Just#copy$default$1(). => method copy$default$1 [covariant typeparam A ]: A -_empty_/Enums.Maybe.Just#copy$default$1().[A] => typeparam A +_empty_/Enums.Maybe.Just#copy$default$1().[A] => typeparam A _empty_/Enums.Maybe.Just#copy(). => method copy [covariant typeparam A ](param value: A): Just[A] _empty_/Enums.Maybe.Just#copy().(value) => param value: A -_empty_/Enums.Maybe.Just#copy().[A] => typeparam A +_empty_/Enums.Maybe.Just#copy().[A] => typeparam A _empty_/Enums.Maybe.Just#ordinal(). => method ordinal => Int <: scala/reflect/Enum#ordinal(). _empty_/Enums.Maybe.Just#value. => val method value A _empty_/Enums.Maybe.Just. => final object Just extends Object { self: Just.type => +4 decls } _empty_/Enums.Maybe.Just.apply(). => method apply [typeparam A ](param value: A): Just[A] _empty_/Enums.Maybe.Just.apply().(value) => param value: A -_empty_/Enums.Maybe.Just.apply().[A] => typeparam A +_empty_/Enums.Maybe.Just.apply().[A] => typeparam A _empty_/Enums.Maybe.Just.toString(). => method toString => String <: scala/Any#toString(). _empty_/Enums.Maybe.Just.unapply(). => method unapply [typeparam A ](param x$1: Just[A]): Just[A] _empty_/Enums.Maybe.Just.unapply().(x$1) => param x$1: Just[A] -_empty_/Enums.Maybe.Just.unapply().[A] => typeparam A +_empty_/Enums.Maybe.Just.unapply().[A] => typeparam A _empty_/Enums.Maybe.None. => case val static enum method None Maybe[Nothing] _empty_/Enums.Maybe.fromOrdinal(). => method fromOrdinal (param ordinal: Int): Maybe[_] forSome { type _ } _empty_/Enums.Maybe.fromOrdinal().(ordinal) => param ordinal: Int @@ -1195,7 +1195,7 @@ _empty_/Enums.Suits.valueOf(). => method valueOf (param $name: String): Suits _empty_/Enums.Suits.valueOf().($name) => param $name: String _empty_/Enums.Suits.values(). => method values => Array[Suits] _empty_/Enums.Tag# => abstract sealed enum class Tag [typeparam A ] extends Object with Enum { self: Tag[A] => +2 decls } -_empty_/Enums.Tag#[A] => typeparam A +_empty_/Enums.Tag#[A] => typeparam A _empty_/Enums.Tag#``(). => primary ctor [typeparam A ](): Tag[A] _empty_/Enums.Tag. => final object Tag extends Object { self: Tag.type => +7 decls } _empty_/Enums.Tag.$values. => private[this] val method $values Array[Tag[_] forSome { type _ }] @@ -1226,33 +1226,33 @@ _empty_/Enums.WeekDays.valueOf(). => method valueOf (param $name: String): WeekD _empty_/Enums.WeekDays.valueOf().($name) => param $name: String _empty_/Enums.WeekDays.values(). => method values => Array[WeekDays] _empty_/Enums.`<:<`# => abstract sealed enum class <:< [contravariant typeparam A , typeparam B ] extends Object with Enum { self: <:<[A, B] => +3 decls } -_empty_/Enums.`<:<`#[A] => contravariant typeparam A -_empty_/Enums.`<:<`#[B] => typeparam B +_empty_/Enums.`<:<`#[A] => contravariant typeparam A +_empty_/Enums.`<:<`#[B] => typeparam B _empty_/Enums.`<:<`#``(). => primary ctor [contravariant typeparam A , typeparam B ](): <:<[A, B] _empty_/Enums.`<:<`. => final object <:< extends Object { self: <:<.type => +6 decls } _empty_/Enums.`<:<`.Refl# => final case enum class Refl [typeparam C ] extends <:<[C, C] { self: Refl[C] => +4 decls } -_empty_/Enums.`<:<`.Refl#[C] => typeparam C +_empty_/Enums.`<:<`.Refl#[C] => typeparam C _empty_/Enums.`<:<`.Refl#``(). => primary ctor [typeparam C ](): Refl[C] _empty_/Enums.`<:<`.Refl#copy(). => method copy [typeparam C ](): Refl[C] -_empty_/Enums.`<:<`.Refl#copy().[C] => typeparam C +_empty_/Enums.`<:<`.Refl#copy().[C] => typeparam C _empty_/Enums.`<:<`.Refl#ordinal(). => method ordinal => Int <: scala/reflect/Enum#ordinal(). _empty_/Enums.`<:<`.Refl. => final object Refl extends Object { self: Refl.type => +4 decls } _empty_/Enums.`<:<`.Refl.apply(). => method apply [typeparam C ](): Refl[C] -_empty_/Enums.`<:<`.Refl.apply().[C] => typeparam C +_empty_/Enums.`<:<`.Refl.apply().[C] => typeparam C _empty_/Enums.`<:<`.Refl.toString(). => method toString => String <: scala/Any#toString(). _empty_/Enums.`<:<`.Refl.unapply(). => method unapply [typeparam C ](param x$1: Refl[C]): true _empty_/Enums.`<:<`.Refl.unapply().(x$1) => param x$1: Refl[C] -_empty_/Enums.`<:<`.Refl.unapply().[C] => typeparam C +_empty_/Enums.`<:<`.Refl.unapply().[C] => typeparam C _empty_/Enums.`<:<`.`given_<:<_T_T`(). => final implicit given method given_<:<_T_T [typeparam T ]: <:<[T, T] -_empty_/Enums.`<:<`.`given_<:<_T_T`().[T] => typeparam T +_empty_/Enums.`<:<`.`given_<:<_T_T`().[T] => typeparam T _empty_/Enums.`<:<`.fromOrdinal(). => method fromOrdinal (param ordinal: Int): <:<[_, _] forSome { type _ ; type _ } _empty_/Enums.`<:<`.fromOrdinal().(ordinal) => param ordinal: Int _empty_/Enums.some1. => val method some1 Option[Int] _empty_/Enums.unwrap(). => method unwrap [typeparam A , typeparam B ](param opt: Option[A])(implicit given param ev: <:<[A, Option[B]]): Option[B] _empty_/Enums.unwrap().(ev) => implicit given param ev: <:<[A, Option[B]] _empty_/Enums.unwrap().(opt) => param opt: Option[A] -_empty_/Enums.unwrap().[A] => typeparam A -_empty_/Enums.unwrap().[B] => typeparam B +_empty_/Enums.unwrap().[A] => typeparam A +_empty_/Enums.unwrap().[B] => typeparam B local0 => param x: Option[B] Occurrences: @@ -1525,7 +1525,7 @@ Symbols: ext/DeckUsage. => final object DeckUsage extends Object { self: DeckUsage.type => +2 decls } ext/DeckUsage.deck. => val method deck Deck ext/Extension$package. => final package object ext extends Object { self: ext.type { opaque type Deck } => +9 decls } -ext/Extension$package.Deck# => opaque type Deck +ext/Extension$package.Deck# => opaque type Deck ext/Extension$package.Deck. => final object Deck extends Object { self: Deck.type => +2 decls } ext/Extension$package.Deck.fooSize(). => method fooSize (param data: Deck): Int ext/Extension$package.Deck.fooSize().(data) => param data: Deck @@ -1539,18 +1539,18 @@ ext/Extension$package.foo().(s) => param s: String ext/Extension$package.readInto(). => method readInto [typeparam T ](param s: String)(implicit given param x$2: Read[T]): Option[T] ext/Extension$package.readInto().(s) => param s: String ext/Extension$package.readInto().(x$2) => implicit given param x$2: Read[T] -ext/Extension$package.readInto().[T] => typeparam T +ext/Extension$package.readInto().[T] => typeparam T ext/Functor# => trait Functor [typeparam F [type _ ]] extends Object { self: Functor[F] => +3 decls } ext/Functor#[F] => typeparam F [type _ ] -ext/Functor#[F][_] => type _ +ext/Functor#[F][_] => type _ ext/Functor#``(). => primary ctor [typeparam F [type _ ]](): Functor[F] ext/Functor#map(). => abstract method map [typeparam T , typeparam U ](param t: F[T])(param f: Function1[T, U]): F[U] ext/Functor#map().(f) => param f: Function1[T, U] ext/Functor#map().(t) => param t: F[T] -ext/Functor#map().[T] => typeparam T -ext/Functor#map().[U] => typeparam U +ext/Functor#map().[T] => typeparam T +ext/Functor#map().[U] => typeparam U ext/Read# => trait Read [covariant typeparam T ] extends Object { self: Read[T] => +3 decls } -ext/Read#[T] => covariant typeparam T +ext/Read#[T] => covariant typeparam T ext/Read#``(). => primary ctor [covariant typeparam T ](): Read[T] ext/Read#fromString(). => abstract method fromString (param s: String): Option[T] ext/Read#fromString().(s) => param s: String @@ -1731,7 +1731,7 @@ Synthetics => 3 entries Symbols: a/b/Givens. => final object Givens extends Object { self: Givens.type => +13 decls } a/b/Givens.Monoid# => trait Monoid [typeparam A ] extends Object { self: Monoid[A] => +4 decls } -a/b/Givens.Monoid#[A] => typeparam A +a/b/Givens.Monoid#[A] => typeparam A a/b/Givens.Monoid#``(). => primary ctor [typeparam A ](): Monoid[A] a/b/Givens.Monoid#combine(). => abstract method combine (param x: A)(param y: A): A a/b/Givens.Monoid#combine().(x) => param x: A @@ -1739,7 +1739,7 @@ a/b/Givens.Monoid#combine().(y) => param y: A a/b/Givens.Monoid#empty(). => abstract method empty => A a/b/Givens.foo(). => method foo [typeparam A ](implicit given param A: Monoid[A]): A a/b/Givens.foo().(A) => implicit given param A: Monoid[A] -a/b/Givens.foo().[A] => typeparam A +a/b/Givens.foo().[A] => typeparam A a/b/Givens.given_Monoid_String. => final implicit given object given_Monoid_String extends Object with Monoid[String] { self: given_Monoid_String.type => +3 decls } a/b/Givens.given_Monoid_String.combine(). => method combine (param x: String)(param y: String): String <: a/b/Givens.Monoid#combine(). a/b/Givens.given_Monoid_String.combine().(x) => param x: String @@ -1754,13 +1754,13 @@ a/b/Givens.int2String#apply().(x) => param x: Int a/b/Givens.int2String(). => final implicit given inline macro int2String => int2String a/b/Givens.sayGoodbye(). => method sayGoodbye [typeparam B ](param any: B): String a/b/Givens.sayGoodbye().(any) => param any: B -a/b/Givens.sayGoodbye().[B] => typeparam B +a/b/Givens.sayGoodbye().[B] => typeparam B a/b/Givens.sayHello(). => method sayHello [typeparam A ](param any: A): String a/b/Givens.sayHello().(any) => param any: A -a/b/Givens.sayHello().[A] => typeparam A +a/b/Givens.sayHello().[A] => typeparam A a/b/Givens.saySoLong(). => method saySoLong [typeparam B ](param any: B): String a/b/Givens.saySoLong().(any) => param any: B -a/b/Givens.saySoLong().[B] => typeparam B +a/b/Givens.saySoLong().[B] => typeparam B a/b/Givens.soLong1. => val method soLong1 String Occurrences: @@ -1868,7 +1868,7 @@ example/ImplicitConversion#tuple. => val method tuple Tuple2[Int, Int] example/ImplicitConversion#x. => val method x Int example/ImplicitConversion. => final object ImplicitConversion extends Object { self: ImplicitConversion.type => +6 decls } example/ImplicitConversion.newAny2stringadd# => final implicit class newAny2stringadd [typeparam A ] extends AnyVal { self: newAny2stringadd[A] => +4 decls } -example/ImplicitConversion.newAny2stringadd#[A] => typeparam A +example/ImplicitConversion.newAny2stringadd#[A] => typeparam A example/ImplicitConversion.newAny2stringadd#`+`(). => method + (param other: String): String example/ImplicitConversion.newAny2stringadd#`+`().(other) => param other: String example/ImplicitConversion.newAny2stringadd#``(). => primary ctor [typeparam A ](param self: A): newAny2stringadd[A] @@ -1876,7 +1876,7 @@ example/ImplicitConversion.newAny2stringadd#``().(self) => param self: A example/ImplicitConversion.newAny2stringadd#self. => private val method self A example/ImplicitConversion.newAny2stringadd(). => final implicit method newAny2stringadd [typeparam A ](param self: A): newAny2stringadd[A] example/ImplicitConversion.newAny2stringadd().(self) => param self: A -example/ImplicitConversion.newAny2stringadd().[A] => typeparam A +example/ImplicitConversion.newAny2stringadd().[A] => typeparam A example/ImplicitConversion.newAny2stringadd. => final object newAny2stringadd extends Object { self: newAny2stringadd.type => +2 decls } Occurrences: @@ -2089,7 +2089,7 @@ givens/InventedNames$package.given_Double(). => final implicit given method give givens/InventedNames$package.given_Double().(x$1) => implicit given param x$1: Int givens/InventedNames$package.given_Float. => final implicit lazy val given method given_Float Float givens/InventedNames$package.given_List_T(). => final implicit given method given_List_T [typeparam T ]: List[T] -givens/InventedNames$package.given_List_T().[T] => typeparam T +givens/InventedNames$package.given_List_T().[T] => typeparam T givens/InventedNames$package.given_String. => final implicit lazy val given method given_String String givens/InventedNames$package.given_X. => final implicit given object given_X extends Object with X { self: given_X.type => +2 decls } givens/InventedNames$package.given_X.doX(). => method doX => Int <: givens/X#doX(). @@ -2101,11 +2101,11 @@ givens/InventedNames$package.given_Y#x$1. => protected implicit val given method givens/InventedNames$package.given_Y(). => final implicit given method given_Y (implicit given param x$1: X): given_Y givens/InventedNames$package.given_Y().(x$1) => implicit given param x$1: X givens/InventedNames$package.given_Z_T# => implicit given class given_Z_T [typeparam T ] extends Object with Z[T] { self: given_Z_T[T] => +3 decls } -givens/InventedNames$package.given_Z_T#[T] => typeparam T +givens/InventedNames$package.given_Z_T#[T] => typeparam T givens/InventedNames$package.given_Z_T#``(). => primary ctor [typeparam T ](): given_Z_T[T] givens/InventedNames$package.given_Z_T#doZ(). => method doZ => List[T] <: givens/Z#doZ(). givens/InventedNames$package.given_Z_T(). => final implicit given method given_Z_T [typeparam T ]: given_Z_T[T] -givens/InventedNames$package.given_Z_T().[T] => typeparam T +givens/InventedNames$package.given_Z_T().[T] => typeparam T givens/InventedNames$package.intValue. => final implicit lazy val given method intValue Int givens/InventedNames$package.x. => val method x given_X.type givens/InventedNames$package.y. => val method y given_Y @@ -2117,7 +2117,7 @@ givens/Y# => trait Y extends Object { self: Y => +2 decls } givens/Y#``(). => primary ctor (): Y givens/Y#doY(). => abstract method doY => String givens/Z# => trait Z [typeparam T ] extends Object { self: Z[T] => +3 decls } -givens/Z#[T] => typeparam T +givens/Z#[T] => typeparam T givens/Z#``(). => primary ctor [typeparam T ](): Z[T] givens/Z#doZ(). => abstract method doZ => List[T] @@ -2292,7 +2292,7 @@ Symbols: example/Local# => class Local extends Object { self: Local => +2 decls } example/Local#``(). => primary ctor (): Local example/Local#a(). => method a (): Int -local0 => typeparam A +local0 => typeparam A local1 => param a: A local2 => local id: [typeparam A ](param a: A): A @@ -2357,10 +2357,10 @@ example/MatchType$package.Concat# => type Concat [typeparam Xs <: Tuple, covari example/MatchType$package.Concat#[Xs] => typeparam Xs <: Tuple example/MatchType$package.Concat#[Ys] => covariant typeparam Ys <: Tuple example/MatchType$package.Elem# => type Elem [typeparam X ] = X match { String => Char, Array[t] => t, Iterable[t] => t } -example/MatchType$package.Elem#[X] => typeparam X -local0 => type t -local1 => type t -local2 => type x +example/MatchType$package.Elem#[X] => typeparam X +local0 => type t +local1 => type t +local2 => type x local3 => type xs <: Tuple Occurrences: @@ -2600,11 +2600,11 @@ Occurrences => 156 entries Symbols: example/Methods# => class Methods [typeparam T ] extends Object { self: Methods[T] => +44 decls } example/Methods#AList# => type AList [typeparam T ] = List[T] -example/Methods#AList#[T] => typeparam T +example/Methods#AList#[T] => typeparam T example/Methods#List# => class List [typeparam T ] extends Object { self: List[T] => +2 decls } -example/Methods#List#[T] => typeparam T +example/Methods#List#[T] => typeparam T example/Methods#List#``(). => primary ctor [typeparam T ](): List[T] -example/Methods#[T] => typeparam T +example/Methods#[T] => typeparam T example/Methods#``(). => primary ctor [typeparam T ](): Methods[T] example/Methods#`m8().`(). => method m8(). (): Nothing example/Methods#`m9().`# => class m9(). extends Object { self: m9(). => +1 decls } @@ -2632,7 +2632,7 @@ example/Methods#m7(). => method m7 [typeparam U ](param c: Methods[T], param l: example/Methods#m7().(c) => param c: Methods[T] example/Methods#m7().(evidence$1) => implicit param evidence$1: Ordering[U] example/Methods#m7().(l) => param l: List[U] -example/Methods#m7().[U] => typeparam U +example/Methods#m7().[U] => typeparam U example/Methods#m9(). => method m9 (param x: m9().): Nothing example/Methods#m9().(x) => param x: m9(). example/Methods#m10(). => method m10 (param x: List[T]): Nothing @@ -2992,18 +2992,18 @@ Occurrences => 18 entries Symbols: _empty_/NewModifiers$package. => final package object _empty_ extends Object { self: _empty_.type { opaque type OpaqueB } => +2 decls } -_empty_/NewModifiers$package.OpaqueB# => opaque type OpaqueB +_empty_/NewModifiers$package.OpaqueB# => opaque type OpaqueB _empty_/NewModifiers. => final object NewModifiers extends Object { self: NewModifiers.type { opaque type A } => +3 decls } -_empty_/NewModifiers.A# => opaque type A +_empty_/NewModifiers.A# => opaque type A _empty_/NewModifiers.foo. => val inline method foo "foo" _empty_/NewModifiersClass# => opaque class NewModifiersClass extends Object { self: Any { opaque type C } & NewModifiersClass => +5 decls } -_empty_/NewModifiersClass#C# => opaque type C +_empty_/NewModifiersClass#C# => opaque type C _empty_/NewModifiersClass#Nested# => opaque class Nested extends Object { self: Any { opaque type NestedOpaque } & Nested => +2 decls } -_empty_/NewModifiersClass#Nested#NestedOpaque# => opaque type NestedOpaque +_empty_/NewModifiersClass#Nested#NestedOpaque# => opaque type NestedOpaque _empty_/NewModifiersClass#Nested#``(). => primary ctor (): Nested _empty_/NewModifiersClass#``(). => primary ctor (): NewModifiersClass _empty_/NewModifiersTrait# => opaque trait NewModifiersTrait extends Object { self: Any { opaque type D } & NewModifiersTrait => +2 decls } -_empty_/NewModifiersTrait#D# => opaque type D +_empty_/NewModifiersTrait#D# => opaque type D _empty_/NewModifiersTrait#``(). => primary ctor (): NewModifiersTrait Occurrences: @@ -3091,13 +3091,13 @@ Occurrences => 49 entries Symbols: prefixes/C# => class C extends Object { self: C => +6 decls } prefixes/C#N. => final object N extends Object { self: N.type => +2 decls } -prefixes/C#N.U# => type U -prefixes/C#T# => type T +prefixes/C#N.U# => type U +prefixes/C#T# => type T prefixes/C#``(). => primary ctor (): C prefixes/C#k1(). => method k1 => U prefixes/C#m1(). => method m1 => T prefixes/M. => final object M extends Object { self: M.type => +3 decls } -prefixes/M.T# => type T +prefixes/M.T# => type T prefixes/M.n1(). => method n1 => T prefixes/O. => final object O extends C { self: O.type => +2 decls } prefixes/O.o1(). => method o1 => O.this.T @@ -3174,13 +3174,13 @@ Synthetics => 3 entries Symbols: example/C# => class C extends Object { self: C => +3 decls } -example/C#T1# => type T1 -example/C#T2# => type T2 +example/C#T1# => type T1 +example/C#T2# => type T2 example/C#``(). => primary ctor (): C example/PickOneRefinement_1# => class PickOneRefinement_1 [typeparam S <: SpecialRefinement { abstract method pickOne [typeparam T ](param as: T*): Option[String] }] extends Object { self: PickOneRefinement_1[S] => +3 decls } example/PickOneRefinement_1#[S] => typeparam S <: SpecialRefinement { abstract method pickOne [typeparam T ](param as: T*): Option[String] } example/PickOneRefinement_1#[S](as) => param as: T* -example/PickOneRefinement_1#[S][T] => typeparam T +example/PickOneRefinement_1#[S][T] => typeparam T example/PickOneRefinement_1#``(). => primary ctor [typeparam S <: SpecialRefinement { abstract method pickOne [typeparam T ](param as: T*): Option[String] }](): PickOneRefinement_1[S] example/PickOneRefinement_1#run(). => method run (param s: S, param as: String*): Option[String] example/PickOneRefinement_1#run().(as) => param as: String* @@ -3189,7 +3189,7 @@ example/PolyHolder# => trait PolyHolder extends Object { self: PolyHolder => +2 example/PolyHolder#``(). => primary ctor (): PolyHolder example/PolyHolder#foo(). => abstract method foo [typeparam T ](param t: T): Any example/PolyHolder#foo().(t) => param t: T -example/PolyHolder#foo().[T] => typeparam T +example/PolyHolder#foo().[T] => typeparam T example/RecOrRefined$package. => final package object example extends Object { self: example.type => +9 decls } example/RecOrRefined$package.C2# => type C2 = C { type T2 = T1 <: example/C#T2#; type T1 <: example/C#T1# } example/RecOrRefined$package.Person# => type Person = Record { abstract val method age Int; abstract val method name String } @@ -3203,9 +3203,9 @@ example/RecOrRefined$package.m4(). => method m4 (param x: PolyHolder { abstract example/RecOrRefined$package.m4().(x) => param x: PolyHolder { abstract method foo [typeparam T ](param t: T): T <: example/PolyHolder#foo(). } example/RecOrRefined$package.m5(). => method m5 [typeparam Z ](param x: Int): PolyHolder { abstract method foo [typeparam T ](param t: T): T <: example/PolyHolder#foo(). } example/RecOrRefined$package.m5().(x) => param x: Int -example/RecOrRefined$package.m5().[Z] => typeparam Z +example/RecOrRefined$package.m5().[Z] => typeparam Z example/RecOrRefined$package.m6# => type m6 [typeparam X ] = PolyHolder { abstract method foo [typeparam T ](param t: T): T <: example/PolyHolder#foo(). } -example/RecOrRefined$package.m6#[X] => typeparam X +example/RecOrRefined$package.m6#[X] => typeparam X example/Record# => class Record extends Object with Selectable { self: Record => +4 decls } example/Record#``(). => primary ctor (param elems: Tuple2[String, Any]*): Record example/Record#``().(elems) => param elems: Tuple2[String, Any]* @@ -3217,9 +3217,9 @@ example/SpecialRefinement# => trait SpecialRefinement extends Object { self: Spe example/SpecialRefinement#``(). => primary ctor (): SpecialRefinement example/SpecialRefinement#pickOne(). => abstract method pickOne [typeparam T ](param as: T*): Option[Any] example/SpecialRefinement#pickOne().(as) => param as: T* -example/SpecialRefinement#pickOne().[T] => typeparam T +example/SpecialRefinement#pickOne().[T] => typeparam T local0 => abstract method pickOne [typeparam T ](param as: T*): Option[String] -local1 => typeparam T +local1 => typeparam T local2 => param as: T* local3 => abstract method pickOne [typeparam T ](param as: T*): Option[String] <: example/SpecialRefinement#pickOne(). local4 => abstract val method x Int @@ -3227,14 +3227,14 @@ local5 => abstract val method x Int local6 => abstract method y => Int local7 => abstract val method x Int local8 => abstract method y => Int -local9 => type z -local10 => typeparam T +local9 => type z +local10 => typeparam T local11 => param t: T local12 => abstract method foo [typeparam T ](param t: T): T <: example/PolyHolder#foo(). -local13 => typeparam T +local13 => typeparam T local14 => param t: T local15 => abstract method foo [typeparam T ](param t: T): T <: example/PolyHolder#foo(). -local16 => typeparam T +local16 => typeparam T local17 => param t: T local18 => abstract method foo [typeparam T ](param t: T): T <: example/PolyHolder#foo(). local19 => abstract val method name String @@ -3456,6 +3456,7 @@ Text => empty Language => Scala Symbols => 12 entries Occurrences => 33 entries +Diagnostics => 1 entries Synthetics => 4 entries Symbols: @@ -3507,6 +3508,11 @@ Occurrences: [20:4..20:13): scalameta -> scala/reflect/Selectable#selectDynamic(). [21:4..21:19): StructuralTypes -> example/StructuralTypes. +Diagnostics: +[14:20..14:23): [warning] Alphanumeric method foo is not declared infix; it should not be used as infix operator. +Instead, use method syntax .foo(...) or backticked identifier `foo`. +The latter can be rewritten automatically under -rewrite -source 3.4-migration. + Synthetics: [12:2..12:6):user => reflectiveSelectable(*) [13:2..13:6):user => reflectiveSelectable(*) @@ -3541,7 +3547,7 @@ example/Synthetic#Contexts.m4(). => method m4 => Nothing example/Synthetic#F# => class F extends Object { self: F => +1 decls } example/Synthetic#F#``(). => primary ctor (): F example/Synthetic#J# => class J [typeparam T ] extends Object { self: J[T] => +4 decls } -example/Synthetic#J#[T] => typeparam T +example/Synthetic#J#[T] => typeparam T example/Synthetic#J#``(). => primary ctor [typeparam T ]()(implicit param evidence$1: Manifest[T]): J[T] example/Synthetic#J#``().(evidence$1) => implicit param evidence$1: Manifest[T] example/Synthetic#J#arr. => val method arr Array[T] @@ -4250,11 +4256,11 @@ Occurrences => 18 entries Symbols: _empty_/Test_depmatch. => final object Test_depmatch extends Object { self: Test_depmatch.type => +4 decls } _empty_/Test_depmatch.Bar# => type Bar [typeparam T ] = T match { Unit => Unit } -_empty_/Test_depmatch.Bar#[T] => typeparam T +_empty_/Test_depmatch.Bar#[T] => typeparam T _empty_/Test_depmatch.Foo# => type Foo = Int { type U } _empty_/Test_depmatch.baz(). => inline macro baz (param foo: Foo): Unit _empty_/Test_depmatch.baz().(foo) => param foo: Foo -local0 => type U +local0 => type U local1 => val local v: Bar[foo.U] Occurrences: @@ -4310,7 +4316,7 @@ Occurrences => 33 entries Symbols: exports/example/Codec# => trait Codec [typeparam T ] extends Object with Decoder[T] with Encoder[T] { self: Codec[T] => +6 decls } -exports/example/Codec#[T] => typeparam T +exports/example/Codec#[T] => typeparam T exports/example/Codec#``(). => primary ctor [typeparam T ](param decode: Decoder[T], param encode: Encoder[T]): Codec[T] exports/example/Codec#``().(decode) => param decode: Decoder[T] exports/example/Codec#``().(encode) => param encode: Encoder[T] @@ -4321,12 +4327,12 @@ exports/example/Codec#encode(). => final method encode (param t: T): Array[Byte] exports/example/Codec#encode().(t) => param t: T exports/example/Codec#encode. => private[this] val method encode Encoder[T] exports/example/Decoder# => trait Decoder [covariant typeparam T ] extends Object { self: Decoder[T] => +3 decls } -exports/example/Decoder#[T] => covariant typeparam T +exports/example/Decoder#[T] => covariant typeparam T exports/example/Decoder#``(). => primary ctor [covariant typeparam T ](): Decoder[T] exports/example/Decoder#decode(). => abstract method decode (param a: Array[Byte]): T exports/example/Decoder#decode().(a) => param a: Array[Byte] exports/example/Encoder# => trait Encoder [contravariant typeparam T ] extends Object { self: Encoder[T] => +3 decls } -exports/example/Encoder#[T] => contravariant typeparam T +exports/example/Encoder#[T] => contravariant typeparam T exports/example/Encoder#``(). => primary ctor [contravariant typeparam T ](): Encoder[T] exports/example/Encoder#encode(). => abstract method encode (param t: T): Array[Byte] exports/example/Encoder#encode().(t) => param t: T @@ -4380,11 +4386,11 @@ Occurrences => 5 entries Symbols: exports/`exports-package$package`. => final package object exports extends Object { self: exports.type => +4 decls } exports/`exports-package$package`.Codec# => final type Codec [typeparam T ] = Codec[T] -exports/`exports-package$package`.Codec#[T] => typeparam T +exports/`exports-package$package`.Codec#[T] => typeparam T exports/`exports-package$package`.Decoder# => final type Decoder [typeparam T ] = Decoder[T] -exports/`exports-package$package`.Decoder#[T] => typeparam T +exports/`exports-package$package`.Decoder#[T] => typeparam T exports/`exports-package$package`.Encoder# => final type Encoder [typeparam T ] = Encoder[T] -exports/`exports-package$package`.Encoder#[T] => typeparam T +exports/`exports-package$package`.Encoder#[T] => typeparam T Occurrences: [0:8..0:15): exports <- exports/ @@ -4426,35 +4432,35 @@ Occurrences => 54 entries Symbols: hk/EitherMonad# => class EitherMonad [typeparam T ] extends Object with Monad[[E] =>> Either[T, E]] { self: EitherMonad[T] => +2 decls } -hk/EitherMonad#[E] => typeparam E -hk/EitherMonad#[T] => typeparam T +hk/EitherMonad#[E] => typeparam E +hk/EitherMonad#[T] => typeparam T hk/EitherMonad#``(). => primary ctor [typeparam T ](): EitherMonad[T] -hk/EitherMonad#``().[E] => typeparam E +hk/EitherMonad#``().[E] => typeparam E hk/Monad# => trait Monad [typeparam M [type _ ]] extends Object { self: Monad[M] => +4 decls } hk/Monad#[M] => typeparam M [type _ ] -hk/Monad#[M][_] => type _ +hk/Monad#[M][_] => type _ hk/Monad#``(). => primary ctor [typeparam M [type _ ]](): Monad[M] hk/Monad#flatMap(). => method flatMap [typeparam A , typeparam B ](param m: M[A])(param f: Function1[A, M[B]]): M[B] hk/Monad#flatMap().(f) => param f: Function1[A, M[B]] hk/Monad#flatMap().(m) => param m: M[A] -hk/Monad#flatMap().[A] => typeparam A -hk/Monad#flatMap().[B] => typeparam B +hk/Monad#flatMap().[A] => typeparam A +hk/Monad#flatMap().[B] => typeparam B hk/Monad#pure(). => method pure [typeparam A ](param a: A): M[A] hk/Monad#pure().(a) => param a: A -hk/Monad#pure().[A] => typeparam A +hk/Monad#pure().[A] => typeparam A hk/hk$package. => final package object hk extends Object { self: hk.type => +5 decls } hk/hk$package.Id# => type Id [typeparam A ] = A -hk/hk$package.Id#[A] => typeparam A +hk/hk$package.Id#[A] => typeparam A hk/hk$package.MapEither# => type MapEither [typeparam K ] = [L] =>> [R] =>> Map[K, Either[L, R]] -hk/hk$package.MapEither#[K] => typeparam K -hk/hk$package.MapEither#[L] => typeparam L -hk/hk$package.MapEither#[R] => typeparam R +hk/hk$package.MapEither#[K] => typeparam K +hk/hk$package.MapEither#[L] => typeparam L +hk/hk$package.MapEither#[R] => typeparam R hk/hk$package.MapKV# => type MapKV [typeparam K ] = [V] =>> Map[K, V] -hk/hk$package.MapKV#[K] => typeparam K -hk/hk$package.MapKV#[V] => typeparam V +hk/hk$package.MapKV#[K] => typeparam K +hk/hk$package.MapKV#[V] => typeparam V hk/hk$package.MapV# => type MapV [type _ ] = [V] =>> Map[String, V] -hk/hk$package.MapV#[V] => typeparam V -hk/hk$package.MapV#[_] => type _ +hk/hk$package.MapV#[V] => typeparam V +hk/hk$package.MapV#[_] => type _ Occurrences: [0:8..0:10): hk <- hk/ @@ -4794,11 +4800,11 @@ _empty_/Concrete#``(). => primary ctor (): Concrete _empty_/Concrete#nullary2(). => method nullary2 => Int <: _empty_/NullaryTest#nullary2(). _empty_/Concrete#nullary3(). => method nullary3 => List[Int] <: _empty_/NullaryTest#nullary3(). _empty_/NullaryTest# => abstract class NullaryTest [typeparam T , typeparam m [typeparam s ]] extends Object { self: NullaryTest[T, m] => +9 decls } -_empty_/NullaryTest#[T] => typeparam T +_empty_/NullaryTest#[T] => typeparam T _empty_/NullaryTest#[m] => typeparam m [typeparam s ] -_empty_/NullaryTest#[m][s] => typeparam s +_empty_/NullaryTest#[m][s] => typeparam s _empty_/NullaryTest#``(). => primary ctor [typeparam T , typeparam m [typeparam s ]](): NullaryTest[T, m] -_empty_/NullaryTest#``().[m][s] => typeparam s +_empty_/NullaryTest#``().[m][s] => typeparam s _empty_/NullaryTest#nullary(). => method nullary => String _empty_/NullaryTest#nullary2(). => abstract method nullary2 => T _empty_/NullaryTest#nullary3(). => abstract method nullary3 => m[T] @@ -5002,9 +5008,9 @@ flags/p/package.AA#x. => private[this] val method x Int flags/p/package.AA#y. => val method y Int flags/p/package.AA#z(). => var method z Int flags/p/package.C# => abstract class C [covariant typeparam T , contravariant typeparam U , typeparam V ] extends Object { self: C[T, U, V] => +10 decls } -flags/p/package.C#[T] => covariant typeparam T -flags/p/package.C#[U] => contravariant typeparam U -flags/p/package.C#[V] => typeparam V +flags/p/package.C#[T] => covariant typeparam T +flags/p/package.C#[U] => contravariant typeparam U +flags/p/package.C#[V] => typeparam V flags/p/package.C#``(). => primary ctor [covariant typeparam T , contravariant typeparam U , typeparam V ](param x: T, param y: U, param z: V): C[T, U, V] flags/p/package.C#``().(x) => param x: T flags/p/package.C#``().(y) => param y: U @@ -5017,11 +5023,11 @@ flags/p/package.C#x. => private[this] val method x T flags/p/package.C#y. => private[this] val method y U flags/p/package.C#z. => private[this] val method z V flags/p/package.S# => class S [@specialized typeparam T ] extends Object { self: S[T] => +2 decls } -flags/p/package.S#[T] => @specialized typeparam T +flags/p/package.S#[T] => @specialized typeparam T flags/p/package.S#``(). => primary ctor [@specialized typeparam T ](): S[T] flags/p/package.T1# => type T1 = Int flags/p/package.T2# => type T2 [typeparam T ] = S[T] -flags/p/package.T2#[T] => typeparam T +flags/p/package.T2#[T] => typeparam T flags/p/package.U# => type U <: Int flags/p/package.V# => type V >: Int flags/p/package.X. => final case object X extends Object with Product with Serializable { self: X.type => +1 decls } @@ -5032,14 +5038,14 @@ flags/p/package.Z#``(). => primary ctor (): Z flags/p/package.`y_=`(). => protected var method y_= (param x$1: Int): Unit flags/p/package.`y_=`().(x$1) => param x$1: Int flags/p/package.m(). => macro m [typeparam TT ]: Int -flags/p/package.m().[TT] => typeparam TT +flags/p/package.m().[TT] => typeparam TT flags/p/package.x. => private[flags/p/] lazy val method x Int flags/p/package.xs1. => val method xs1 Nothing flags/p/package.y(). => protected implicit var method y Int flags/p/package.z(). => method z (param pp: Int): Int flags/p/package.z().(pp) => param pp: Int local0 => val local xs2: Nothing -local1 => type t +local1 => type t Occurrences: [0:8..0:13): flags <- flags/ @@ -5154,7 +5160,7 @@ local3 => final class $anon extends Object { self: $anon => +2 decls } local5 => final class $anon extends M with N { self: $anon => +1 decls } local7 => method k => Int local8 => final class $anon extends M with N { self: $anon => +2 decls } -local10 => typeparam T +local10 => typeparam T local11 => type L [typeparam T ] = List[T] types/B# => class B extends Object { self: B => +1 decls } types/B#``(). => primary ctor (): B @@ -5199,7 +5205,7 @@ types/Test.C#ClassInfoType2# => class ClassInfoType2 extends B { self: ClassInfo types/Test.C#ClassInfoType2#``(). => primary ctor (): ClassInfoType2 types/Test.C#ClassInfoType2#x(). => method x => Int types/Test.C#ClassInfoType3# => trait ClassInfoType3 [typeparam T ] extends Object { self: ClassInfoType3[T] => +2 decls } -types/Test.C#ClassInfoType3#[T] => typeparam T +types/Test.C#ClassInfoType3#[T] => typeparam T types/Test.C#ClassInfoType3#``(). => primary ctor [typeparam T ](): ClassInfoType3[T] types/Test.C#Either. => val method Either Either.type types/Test.C#MethodType. => final object MethodType extends Object { self: MethodType.type => +7 decls } @@ -5209,7 +5215,7 @@ types/Test.C#MethodType.m5(). => method m5 (param x: Int): Int types/Test.C#MethodType.m5().(x) => param x: Int types/Test.C#MethodType.m6(). => method m6 [typeparam T ](param x: T): T types/Test.C#MethodType.m6().(x) => param x: T -types/Test.C#MethodType.m6().[T] => typeparam T +types/Test.C#MethodType.m6().[T] => typeparam T types/Test.C#MethodType.x1(). => method x1 => Int types/Test.C#MethodType.x2(). => method x2 => Int types/Test.C#RepeatedType# => case class RepeatedType extends Object with Product with Serializable { self: RepeatedType => +4 decls } @@ -5226,15 +5232,15 @@ types/Test.C#RepeatedType.toString(). => method toString => String <: scala/Any# types/Test.C#RepeatedType.unapplySeq(). => method unapplySeq (param x$1: RepeatedType): RepeatedType types/Test.C#RepeatedType.unapplySeq().(x$1) => param x$1: RepeatedType types/Test.C#TypeType. => final object TypeType extends Object { self: TypeType.type => +6 decls } -types/Test.C#TypeType.T1# => type T1 +types/Test.C#TypeType.T1# => type T1 types/Test.C#TypeType.T4# => type T4 = C types/Test.C#TypeType.T5# => type T5 [typeparam U ] = U -types/Test.C#TypeType.T5#[U] => typeparam U +types/Test.C#TypeType.T5#[U] => typeparam U types/Test.C#TypeType.m2(). => method m2 [typeparam T2 = C]: Nothing types/Test.C#TypeType.m2().[T2] => typeparam T2 = C types/Test.C#TypeType.m3(). => method m3 [typeparam M3 [type _ ]]: Nothing types/Test.C#TypeType.m3().[M3] => typeparam M3 [type _ ] -types/Test.C#TypeType.m3().[M3][_] => type _ +types/Test.C#TypeType.m3().[M3][_] => type _ types/Test.C#``(). => primary ctor (): C types/Test.C#annType1. => val method annType1 T @ann[T] types/Test.C#annType2. => val method annType2 T @ann1 @ann2 @@ -5257,7 +5263,7 @@ types/Test.C#thisType1. => val method thisType1 C.this.type types/Test.C#thisType2. => val method thisType2 C.this.type types/Test.C#typeLambda1(). => method typeLambda1 [typeparam M [type _ ]]: Nothing types/Test.C#typeLambda1().[M] => typeparam M [type _ ] -types/Test.C#typeLambda1().[M][_] => type _ +types/Test.C#typeLambda1().[M][_] => type _ types/Test.C#typeRef1. => val method typeRef1 C types/Test.C#typeRef2. => val method typeRef2 p.C types/Test.C#typeRef3. => val method typeRef3 T#C @@ -5282,7 +5288,7 @@ types/Test.N# => trait N extends Object { self: N => +2 decls } types/Test.N#``(). => primary ctor (): N types/Test.N#n(). => method n => Int types/ann# => class ann [typeparam T ] extends Annotation with StaticAnnotation { self: ann[T] => +3 decls } -types/ann#[T] => typeparam T +types/ann#[T] => typeparam T types/ann#``(). => primary ctor [typeparam T ](param x: T): ann[T] types/ann#``().(x) => param x: T types/ann#x. => private[this] val method x T diff --git a/tests/warn/i22681.scala b/tests/warn/i22681.scala new file mode 100644 index 000000000000..49ad9c19654d --- /dev/null +++ b/tests/warn/i22681.scala @@ -0,0 +1,17 @@ + +//> using options -Wunused:all + +trait T: + def t: Int + +class C: + def f: Runnable { def u: Int } = new Runnable with T: + private def v = 42 // avoid g judged too trivial to warn + def run() = () + def g = v // LTS specific: no warn, althougheffectively private member is unused + def t = v // nowarn + def u = v // nowarn because leaked by refinement + val v: Runnable { def u: Int } = new Runnable: + private def v = 42 // avoid g judged too trivial to warn + def run() = () + def u = v // nowarn because leaked by refinement From f65d04f5b1a255e9ee31912f4814969e2645410d Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Fri, 25 Apr 2025 08:17:27 +0200 Subject: [PATCH 159/505] First cut at nowarn refinement members [Cherry-picked 133dcb3bf765f43e160ea70699bc399f35fb96b4][modified] From adab04ae4c9ddd8bd4898d59a744cec770a96840 Mon Sep 17 00:00:00 2001 From: Jan Chyb Date: Wed, 18 Dec 2024 15:17:07 +0100 Subject: [PATCH 160/505] Make Ref.apply() return trees usable in the largest scope possible Previously for symbols contained in objects (prefixed by, let's say, 'pre'), we would return: * an Ident if pre contained only static object and packages; * Select(This(moduleClassSymbol), sym) if a prefix contained a class. However, this meant that in the second case, the generated tree would require the macro to be expanded inside of the object, even though it should be enough to just expand inside of the innermost class. This was unexpected and confusing, so it was changed to not return innermost module classes wrapped with This(). [Cherry-picked 238ba458b491c06e9f492673607157619b61d007] --- compiler/src/dotty/tools/dotc/ast/tpd.scala | 15 +++++++ .../tools/dotc/core/SymDenotations.scala | 1 - .../quoted/runtime/impl/QuotesImpl.scala | 2 +- library/src/scala/quoted/Quotes.scala | 6 ++- tests/pos-macros/i20349a/Macro_1.scala | 11 +++++ tests/pos-macros/i20349a/Test_2.scala | 16 +++++++ tests/pos-macros/i20349b/Macro_1.scala | 43 +++++++++++++++++++ tests/pos-macros/i20349b/Test_2.scala | 14 ++++++ 8 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 tests/pos-macros/i20349a/Macro_1.scala create mode 100644 tests/pos-macros/i20349a/Test_2.scala create mode 100644 tests/pos-macros/i20349b/Macro_1.scala create mode 100644 tests/pos-macros/i20349b/Test_2.scala diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index c119dfd8d982..6ce8d93af76a 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -477,6 +477,21 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def ref(sym: Symbol)(using Context): Tree = ref(NamedType(sym.owner.thisType, sym.name, sym.denot)) + // Like `ref`, but avoids wrapping innermost module class references with This(), + // instead mapping those to objects, so that the resulting trees can be used in + // largest scope possible (method added for macros) + def generalisedRef(sym: Symbol)(using Context): Tree = + // Removes ThisType from inner module classes, replacing those with references to objects + def simplifyThisTypePrefix(tpe: Type)(using Context): Type = + tpe match + case ThisType(tref @ TypeRef(prefix, _)) if tref.symbol.flags.is(Module) => + TermRef(simplifyThisTypePrefix(prefix), tref.symbol.companionModule) + case TypeRef(prefix, designator) => + TypeRef(simplifyThisTypePrefix(prefix), designator) + case _ => + tpe + ref(NamedType(simplifyThisTypePrefix(sym.owner.thisType), sym.name, sym.denot)) + private def followOuterLinks(t: Tree)(using Context) = t match { case t: This if ctx.erasedTypes && !(t.symbol == ctx.owner.enclosingClass || t.symbol.isStaticOwner) => // after erasure outer paths should be respected diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 0e068eff2cfd..340197ffc4a0 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1945,7 +1945,6 @@ object SymDenotations { /** The this-type depends on the kind of class: * - for a package class `p`: ThisType(TypeRef(Noprefix, p)) - * - for a module class `m`: A term ref to m's source module. * - for all other classes `c` with owner `o`: ThisType(TypeRef(o.thisType, c)) */ override def thisType(using Context): Type = { diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index a666feace741..b6d0eae2fbbb 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -454,7 +454,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler withDefaultPos(tpd.ref(tp).asInstanceOf[tpd.RefTree]) def apply(sym: Symbol): Ref = assert(sym.isTerm, s"expected a term symbol, but received $sym") - val refTree = tpd.ref(sym) match + val refTree = tpd.generalisedRef(sym) match case t @ tpd.This(ident) => // not a RefTree, so we need to work around this - issue #19732 // ident in `This` can be a TypeIdent of sym, so we manually prepare the ref here, // knowing that the owner is actually `This`. diff --git a/library/src/scala/quoted/Quotes.scala b/library/src/scala/quoted/Quotes.scala index c5d0022b6cf5..544e9119a770 100644 --- a/library/src/scala/quoted/Quotes.scala +++ b/library/src/scala/quoted/Quotes.scala @@ -878,10 +878,14 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => * If `sym` refers to a class member `foo` in class `C`, * returns a tree representing `C.this.foo`. * + * If `sym` refers to an object member `foo` in object C, itself in prefix + * `pre` (which might include `.this`, if it contains a class), + * returns `pre.C.foo`. + * * If `sym` refers to a local definition `foo`, returns * a tree representing `foo`. * - * @note In both cases, the constructed tree should only + * @note In all cases, the constructed tree should only * be spliced into the places where such accesses make sense. * For example, it is incorrect to have `C.this.foo` outside * the class body of `C`, or have `foo` outside the lexical diff --git a/tests/pos-macros/i20349a/Macro_1.scala b/tests/pos-macros/i20349a/Macro_1.scala new file mode 100644 index 000000000000..41c5083b328c --- /dev/null +++ b/tests/pos-macros/i20349a/Macro_1.scala @@ -0,0 +1,11 @@ +import scala.quoted.* + +object Macros { + def valuesImpl[A: Type](using Quotes): Expr[Any] = { + import quotes.reflect.* + val symbol = TypeRepr.of[A].typeSymbol.fieldMember("value") + Ref(symbol).asExprOf[Any] + } + + transparent inline def values[A]: Any = ${ valuesImpl[A] } +} diff --git a/tests/pos-macros/i20349a/Test_2.scala b/tests/pos-macros/i20349a/Test_2.scala new file mode 100644 index 000000000000..4569c501e055 --- /dev/null +++ b/tests/pos-macros/i20349a/Test_2.scala @@ -0,0 +1,16 @@ + +class Cls{ + object a { + object domain { + val value = "" + } + } + Macros.values[a.domain.type] +} + +object Test { + lazy val script = new Cls() + def main(args: Array[String]): Unit = + val _ = script.hashCode() + ??? +} diff --git a/tests/pos-macros/i20349b/Macro_1.scala b/tests/pos-macros/i20349b/Macro_1.scala new file mode 100644 index 000000000000..413274b4b516 --- /dev/null +++ b/tests/pos-macros/i20349b/Macro_1.scala @@ -0,0 +1,43 @@ +import scala.quoted.* + +object Macros { + + + def valuesImpl[A: Type](using quotes: Quotes): Expr[List[A]] = { + import quotes.*, quotes.reflect.* + + extension (sym: Symbol) + def isPublic: Boolean = !sym.isNoSymbol && + !(sym.flags.is(Flags.Private) || sym.flags.is(Flags.PrivateLocal) || sym.flags.is(Flags.Protected) || + sym.privateWithin.isDefined || sym.protectedWithin.isDefined) + + def isSealed[A: Type]: Boolean = + TypeRepr.of[A].typeSymbol.flags.is(Flags.Sealed) + + def extractSealedSubtypes[A: Type]: List[Type[?]] = { + def extractRecursively(sym: Symbol): List[Symbol] = + if sym.flags.is(Flags.Sealed) then sym.children.flatMap(extractRecursively) + else if sym.flags.is(Flags.Enum) then List(sym.typeRef.typeSymbol) + else if sym.flags.is(Flags.Module) then List(sym.typeRef.typeSymbol.moduleClass) + else List(sym) + + extractRecursively(TypeRepr.of[A].typeSymbol).distinct.map(typeSymbol => + typeSymbol.typeRef.asType + ) + } + + if isSealed[A] then { + val refs = extractSealedSubtypes[A].flatMap { tpe => + val sym = TypeRepr.of(using tpe).typeSymbol + val isCaseVal = sym.isPublic && sym.flags + .is(Flags.Case | Flags.Enum) && (sym.flags.is(Flags.JavaStatic) || sym.flags.is(Flags.StableRealizable)) + + if (isCaseVal) then List(Ref(sym).asExprOf[A]) + else Nil + } + Expr.ofList(refs) + } else '{ Nil } + } + + inline def values[A]: List[A] = ${ valuesImpl[A] } +} diff --git a/tests/pos-macros/i20349b/Test_2.scala b/tests/pos-macros/i20349b/Test_2.scala new file mode 100644 index 000000000000..a392a636dc44 --- /dev/null +++ b/tests/pos-macros/i20349b/Test_2.scala @@ -0,0 +1,14 @@ +class Test { + object domain { + enum PaymentMethod: + case PayPal(email: String) + case Card(digits: Long, name: String) + case Cash + } + println(Macros.values[domain.PaymentMethod]) +} +object Test { + lazy val script = new Test() + def main(args: Array[String]): Unit = + val _ = script.hashCode() +} From 1af6ec1aab7586c93765db7cb8bd1c4026fb091c Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Fri, 7 Mar 2025 10:48:54 -0800 Subject: [PATCH 161/505] Restore resolving prefixes of implicit Ident --- .../tools/dotc/transform/CheckUnused.scala | 44 ++++++++++++------- tests/warn/i22681.scala | 2 +- tests/warn/i22744.scala | 35 +++++++++++++++ 3 files changed, 65 insertions(+), 16 deletions(-) create mode 100644 tests/warn/i22744.scala diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index bb298b1bcc16..61c18180420f 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -58,6 +58,12 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha || tree.srcPos.isZeroExtentSynthetic || refInfos.inlined.exists(_.sourcePos.contains(tree.srcPos.sourcePos)) if resolving && !ignoreTree(tree) then + def loopOverPrefixes(prefix: Type, depth: Int): Unit = + if depth < 10 && prefix.exists && !prefix.classSymbol.isEffectiveRoot then + resolveUsage(prefix.classSymbol, nme.NO_NAME, NoPrefix) + loopOverPrefixes(prefix.normalizedPrefix, depth + 1) + if tree.srcPos.isZeroExtentSynthetic then + loopOverPrefixes(tree.typeOpt.normalizedPrefix, depth = 0) resolveUsage(tree.symbol, tree.name, tree.typeOpt.importPrefix.skipPackageObject) else if tree.hasType then resolveUsage(tree.tpe.classSymbol, tree.name, tree.tpe.importPrefix.skipPackageObject) @@ -116,7 +122,7 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha tree override def prepareForMatch(tree: Match)(using Context): Context = - // exonerate case.pat against tree.selector (simple var pat only for now) + // allow case.pat against tree.selector (simple var pat only for now) tree.selector match case Ident(nm) => tree.cases.foreach(k => allowVariableBindings(List(nm), List(k.pat))) case _ => @@ -138,9 +144,9 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha refInfos.inlined.push(tree.call.srcPos) ctx override def transformInlined(tree: Inlined)(using Context): tree.type = + transformAllDeep(tree.expansion) // traverse expansion with nonempty inlined stack to avoid registering defs val _ = refInfos.inlined.pop() - if !tree.call.isEmpty && phaseMode.eq(PhaseMode.Aggregate) then - transformAllDeep(tree.call) + transformAllDeep(tree.call) tree override def prepareForBind(tree: Bind)(using Context): Context = @@ -158,11 +164,7 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha traverseAnnotations(tree.symbol) if tree.name.startsWith("derived$") && tree.hasType then def loop(t: Tree): Unit = t match - case Ident(name) => - val target = - val ts0 = t.tpe.typeSymbol - if ts0.is(ModuleClass) then ts0.companionModule else ts0 - resolveUsage(target, name, t.tpe.underlyingPrefix.skipPackageObject) + case Ident(name) => resolveUsage(t.tpe.typeSymbol, name, t.tpe.underlyingPrefix.skipPackageObject) case Select(t, _) => loop(t) case _ => tree.getAttachment(OriginalTypeClass).foreach(loop) @@ -272,8 +274,9 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha * For Select, lint does not look up `.scala` (so top-level syms look like magic) but records `scala.Int`. * For Ident, look-up finds the root import as usual. A competing import is OK because higher precedence. */ - def resolveUsage(sym: Symbol, name: Name, prefix: Type)(using Context): Unit = + def resolveUsage(sym0: Symbol, name: Name, prefix: Type)(using Context): Unit = import PrecedenceLevels.* + val sym = sym0.userSymbol def matchingSelector(info: ImportInfo): ImportSelector | Null = val qtpe = info.site @@ -319,7 +322,7 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha // Avoid spurious NoSymbol and also primary ctors which are never warned about. // Selections C.this.toString should be already excluded, but backtopped here for eq, etc. - if !sym.exists || sym.isPrimaryConstructor || defn.topClasses(sym.owner) then return + if !sym.exists || sym.isPrimaryConstructor || sym.isEffectiveRoot || defn.topClasses(sym.owner) then return // Find the innermost, highest precedence. Contexts have no nesting levels but assume correctness. // If the sym is an enclosing definition (the owner of a context), it does not count toward usages. @@ -454,11 +457,15 @@ object CheckUnused: if !tree.name.isInstanceOf[DerivedName] then pats.addOne((tree.symbol, tree.namePos)) case tree: NamedDefTree => - if (tree.symbol ne NoSymbol) && !tree.name.isWildcard && !tree.hasAttachment(NoWarn) then - defs.addOne((tree.symbol, tree.namePos)) + if (tree.symbol ne NoSymbol) + && !tree.name.isWildcard + && !tree.hasAttachment(NoWarn) + && !tree.symbol.is(ModuleVal) // track only the ModuleClass using the object symbol, with correct namePos + then + defs.addOne((tree.symbol.userSymbol, tree.namePos)) case _ => if tree.symbol ne NoSymbol then - defs.addOne((tree.symbol, tree.srcPos)) + defs.addOne((tree.symbol, tree.srcPos)) // TODO is this a code path val inlined = Stack.empty[SrcPos] // enclosing call.srcPos of inlined code (expansions) var inliners = 0 // depth of inline def (not inlined yet) @@ -518,7 +525,7 @@ object CheckUnused: def checkPrivate(sym: Symbol, pos: SrcPos) = if ctx.settings.WunusedHas.privates && !sym.isPrimaryConstructor - && sym.is(Private, butNot = SelfName | Synthetic | CaseAccessor) + && !sym.isOneOf(SelfName | Synthetic | CaseAccessor) && !sym.name.is(BodyRetainerName) && !sym.isSerializationSupport && !(sym.is(Mutable) && sym.isSetter && sym.owner.is(Trait)) // tracks sym.underlyingSymbol sibling getter @@ -763,7 +770,7 @@ object CheckUnused: for (sym, pos) <- infos.defs.iterator if !sym.hasAnnotation(defn.UnusedAnnot) do if infos.refs(sym) then checkUnassigned(sym, pos) - else if sym.is(Private, butNot = ParamAccessor) then + else if sym.isEffectivelyPrivate then checkPrivate(sym, pos) else if sym.is(Param, butNot = Given | Implicit) then checkParam(sym, pos) @@ -903,6 +910,13 @@ object CheckUnused: val base = if owner.classInfo.selfInfo != NoType then owner.thisType else owner.info base.baseClasses.drop(1).iterator.exists(sym.overriddenSymbol(_).exists) } + def isEffectivelyPrivate: Boolean = + sym.is(Private, butNot = ParamAccessor) + || sym.owner.isAnonymousClass && !sym.nextOverriddenSymbol.exists + // pick the symbol the user wrote for purposes of tracking + inline def userSymbol: Symbol= + if sym.denot.is(ModuleClass) then sym.denot.companionModule else sym + extension (sel: ImportSelector) def boundTpe: Type = sel.bound match case untpd.TypedSplice(tree) => tree.tpe diff --git a/tests/warn/i22681.scala b/tests/warn/i22681.scala index 49ad9c19654d..f8b535084f6c 100644 --- a/tests/warn/i22681.scala +++ b/tests/warn/i22681.scala @@ -8,7 +8,7 @@ class C: def f: Runnable { def u: Int } = new Runnable with T: private def v = 42 // avoid g judged too trivial to warn def run() = () - def g = v // LTS specific: no warn, althougheffectively private member is unused + def g = v // warn, effectively private member is unused def t = v // nowarn def u = v // nowarn because leaked by refinement val v: Runnable { def u: Int } = new Runnable: diff --git a/tests/warn/i22744.scala b/tests/warn/i22744.scala new file mode 100644 index 000000000000..655a14b162ce --- /dev/null +++ b/tests/warn/i22744.scala @@ -0,0 +1,35 @@ + +//> using options -Wunused:privates -Werror + +object test { + private trait Foo[A] { val value: A } + + private object Foo { // no warn prefix of implicit value + given int: Foo[Int] = new Foo[Int] { val value = 1 } + } + + val i = summon[Foo[Int]].value +} + +object supplement { + private trait Foo[A] { val value: A } + + private object Foo { // no warn prefix of implicit value + given int: Foo[Int] = new Foo[Int] { val value = 1 } + } + + private def fooValue[A](using f: Foo[A]): A = f.value + + val i = fooValue[Int] +} + +package p: + private trait Foo[A] { val value: A } + + private object Foo { // no warn prefix of implicit value + given int: Foo[Int] = new Foo[Int] { val value = 1 } + } + + private def fooValue[A](using f: Foo[A]): A = f.value + + val i = fooValue[Int] From f8cb874c715573d187f26ad5d4942ffcd4a26993 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Fri, 25 Apr 2025 08:22:25 +0200 Subject: [PATCH 162/505] Restore resolving prefixes of implicit Ident [Cherry-picked d1852bf26f84cae03674755f77006b2ac6fe7e35][modified] From b7bb55f30bf076d5a752b7ced918fc9b7fbb7c56 Mon Sep 17 00:00:00 2001 From: HarrisL2 Date: Mon, 10 Mar 2025 06:19:15 -0400 Subject: [PATCH 163/505] Scaladoc tool: render `@deprecated` correctly even when named arguments weren't used (#21925) Fixes #20118 Still need a test case for this issue using jsoup [Cherry-picked 120f305b17afc72bacf33da85386a41665a568d6] --- scaladoc-testcases/src/tests/deprecated.scala | 63 +++++++++++++++---- .../scaladoc/renderers/MemberRenderer.scala | 7 ++- .../TranslatableSignaturesTestCases.scala | 2 + 3 files changed, 58 insertions(+), 14 deletions(-) diff --git a/scaladoc-testcases/src/tests/deprecated.scala b/scaladoc-testcases/src/tests/deprecated.scala index 983ff7e012c7..f02f1363e9ea 100644 --- a/scaladoc-testcases/src/tests/deprecated.scala +++ b/scaladoc-testcases/src/tests/deprecated.scala @@ -2,22 +2,61 @@ package tests package deprecated class A: - def defInt: Int = 1 + def defInt: Int + = 1 @deprecated(message = "1") - def def1: 1 = 1 + def def1: 1 + = 1 @deprecated("reason") - val valInt: Int = 1 - val val1: 1 = 1 - var varInt: Int = 1 - var var1: 1 = 1 + val valInt: Int + = 1 + val val1: 1 + = 1 + var varInt: Int + = 1 + var var1: 1 + = 1 class InnerA: - val innerVal: Int = 1 + val innerVal: Int + = 1 class B extends A: @deprecated(since = "1", message = "some reason") - def x: Int = 1 - val y: Int = 1 + def x: Int + = 1 + val y: Int + = 1 - -@java.lang.Deprecated -class JavaDeprecated +class C: + /** zero */ + @deprecated + def noInfo: Int + = 0 + /** one */ + @deprecated() + def noInfo2: Int + = 0 + /** two */ + @deprecated("without names", "2.10.0") + def noNames: Int + = 0 + /** three */ + @deprecated(message = "with names", since = "2.10.0") + def withNames: Int + = 1 + /** four */ + @deprecated(since = "2.10.0", message = "backwards names") + def backwardNames: Int + = 2 + /** five */ + @deprecated("only message") + def onlyUnnamedMessage: Int + = 0 + /** six */ + @deprecated(message = "only named message") + def onlyNamedMessage: Int + = 1 + /** seven */ + @deprecated(since = "2.10.0") + def onlyNamedSince: Int + = 2 \ No newline at end of file diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/MemberRenderer.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/MemberRenderer.scala index 7e5394b598fd..98479b8b95ea 100644 --- a/scaladoc/src/dotty/tools/scaladoc/renderers/MemberRenderer.scala +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/MemberRenderer.scala @@ -80,9 +80,12 @@ class MemberRenderer(signatureRenderer: SignatureRenderer)(using DocContext) ext signatureRenderer.renderLink(stripQuotes(text), dri) case Annotation.UnresolvedParameter(_, value) => stripQuotes(value) + // named arguments might be used, so we can't always rely on the order of the parameters val (named, unnamed) = a.params.partition(_.name.nonEmpty) - val message = named.find(_.name.get == "message") - val since = named.find(_.name.get == "since") + val message: Option[Annotation.AnnotationParameter] = + named.find(_.name.get == "message").fold(unnamed.lift(0))(Some(_)) + val since: Option[Annotation.AnnotationParameter] = + named.find(_.name.get == "since").fold(unnamed.lift(1))(Some(_)) val content = ( Seq( diff --git a/scaladoc/test/dotty/tools/scaladoc/signatures/TranslatableSignaturesTestCases.scala b/scaladoc/test/dotty/tools/scaladoc/signatures/TranslatableSignaturesTestCases.scala index b658bfcdedc0..78de0ce67124 100644 --- a/scaladoc/test/dotty/tools/scaladoc/signatures/TranslatableSignaturesTestCases.scala +++ b/scaladoc/test/dotty/tools/scaladoc/signatures/TranslatableSignaturesTestCases.scala @@ -55,6 +55,8 @@ class GivenSignatures extends SignatureTest("givenSignatures", SignatureTest.all class Annotations extends SignatureTest("annotations", SignatureTest.all) +class Deprecated extends SignatureTest("deprecated", SignatureTest.all) + class InheritanceLoop extends SignatureTest("inheritanceLoop", SignatureTest.all) class InheritedMembers extends SignatureTest("inheritedMembers2", SignatureTest.all.filter(_ != "class"), From f76ccd37248839f9ea21cc2ce9890857c0d8929f Mon Sep 17 00:00:00 2001 From: aherlihy Date: Thu, 9 Jan 2025 15:12:03 -0500 Subject: [PATCH 164/505] Skeleton :require [Cherry-picked f8cd3ba2dd9f03c061c94b370df3623eca16c2e5] --- compiler/src/dotty/tools/repl/ParseResult.scala | 8 ++++++++ compiler/src/dotty/tools/repl/ReplDriver.scala | 12 ++++++++++++ .../test/dotty/tools/repl/TabcompleteTests.scala | 1 + 3 files changed, 21 insertions(+) diff --git a/compiler/src/dotty/tools/repl/ParseResult.scala b/compiler/src/dotty/tools/repl/ParseResult.scala index dd4c5d80a9e1..da5ae8807d99 100644 --- a/compiler/src/dotty/tools/repl/ParseResult.scala +++ b/compiler/src/dotty/tools/repl/ParseResult.scala @@ -52,6 +52,13 @@ object Load { val command: String = ":load" } +/** `:require ` adds a jar to the classpath + */ +case class Require(path: String) extends Command +object Require { + val command: String = ":require" +} + /** `:kind ` display the kind of a type. see also :help kind */ case class KindOf(expr: String) extends Command @@ -153,6 +160,7 @@ object ParseResult { Imports.command -> (_ => Imports), KindOf.command -> (arg => KindOf(arg)), Load.command -> (arg => Load(arg)), + Require.command -> (arg => Require(arg)), TypeOf.command -> (arg => TypeOf(arg)), DocOf.command -> (arg => DocOf(arg)), Settings.command -> (arg => Settings(arg)), diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 114fa607f945..123e13c09a27 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -513,6 +513,18 @@ class ReplDriver(settings: Array[String], state } + case Require(path) => + val file = new JFile(path) + if (file.exists) { +// val contents = Using(scala.io.Source.fromFile(file, StandardCharsets.UTF_8.name))(_.mkString).get +// run(contents) + ??? + } + else { + out.println(s"""Couldn't find file "${file.getCanonicalPath}"""") + state + } + case KindOf(expr) => out.println(s"""The :kind command is not currently supported.""") state diff --git a/compiler/test/dotty/tools/repl/TabcompleteTests.scala b/compiler/test/dotty/tools/repl/TabcompleteTests.scala index a881b828ec75..3cfe976d8169 100644 --- a/compiler/test/dotty/tools/repl/TabcompleteTests.scala +++ b/compiler/test/dotty/tools/repl/TabcompleteTests.scala @@ -218,6 +218,7 @@ class TabcompleteTests extends ReplTest { ":imports", ":kind", ":load", + ":require", ":quit", ":reset", ":settings", From 4c9e2bd911a2b1b8010232275d3e1561e4860a67 Mon Sep 17 00:00:00 2001 From: aherlihy Date: Thu, 9 Jan 2025 17:11:09 -0500 Subject: [PATCH 165/505] find class names, need to add URL to loader [Cherry-picked d528014801d4c1a31f1b21393b143545bfdf7da0] --- .../src/dotty/tools/repl/ParseResult.scala | 2 +- .../src/dotty/tools/repl/ReplDriver.scala | 43 +++++++++++++++---- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/compiler/src/dotty/tools/repl/ParseResult.scala b/compiler/src/dotty/tools/repl/ParseResult.scala index da5ae8807d99..409572aeacf6 100644 --- a/compiler/src/dotty/tools/repl/ParseResult.scala +++ b/compiler/src/dotty/tools/repl/ParseResult.scala @@ -52,7 +52,7 @@ object Load { val command: String = ":load" } -/** `:require ` adds a jar to the classpath +/** `:require ` adds a jar to the classpath */ case class Require(path: String) extends Command object Require { diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 123e13c09a27..a572e952ac5f 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -38,6 +38,7 @@ import org.jline.reader.* import scala.annotation.tailrec import scala.collection.mutable import scala.jdk.CollectionConverters.* +import scala.tools.asm.ClassReader import scala.util.control.NonFatal import scala.util.Using @@ -514,16 +515,40 @@ class ReplDriver(settings: Array[String], } case Require(path) => - val file = new JFile(path) - if (file.exists) { -// val contents = Using(scala.io.Source.fromFile(file, StandardCharsets.UTF_8.name))(_.mkString).get -// run(contents) - ??? - } - else { - out.println(s"""Couldn't find file "${file.getCanonicalPath}"""") + val f = new JFile(path) + val jarFile = AbstractFile.getDirectory(path) + if (!f.exists || jarFile == null) + out.println(s"""Cannot add "$path" to classpath.""") + state + else + def flatten(f: AbstractFile): Iterator[AbstractFile] = + if (f.isClassContainer) f.iterator.flatMap(flatten) + else Iterator(f) + + val entries = flatten(jarFile) + + def classNameOf(classFile: AbstractFile): String = { + val input = classFile.input + try { + val reader = new ClassReader(input) + reader.getClassName.replace('/', '.') + } finally { + input.close() + } + } + + val clsl = rendering.classLoader()(using state.context) + +// def alreadyDefined(clsName: String) = classLoader.tryToLoadClass(clsName).isDefined +// val existingClass = entries.filter(_.ext.isClass).map(classNameOf).find(alreadyDefined) + +// if (existingClass.nonEmpty) out.println(s"The path '$f' cannot be loaded, it contains a classfile that already exists on the classpath: ${existingClass.get}") +// else { +// intp.addUrlsToClassPath(f.toURI.toURL) +// out.println(s"Added '$path' to classpath.") +// out.println("Added '%s'. Your new classpath is:\n\"%s\"".format(f.path, intp.classPathString)) +// } state - } case KindOf(expr) => out.println(s"""The :kind command is not currently supported.""") From b58c3b99f9fa504ccba15261d8e3361807697557 Mon Sep 17 00:00:00 2001 From: aherlihy Date: Thu, 9 Jan 2025 17:42:09 -0500 Subject: [PATCH 166/505] Attempt to update class loader, not successful [Cherry-picked f4968e795b31970a0fc7f553a8f96ceebaaa482b] --- compiler/src/dotty/tools/repl/ReplDriver.scala | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index a572e952ac5f..1c81db694406 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -537,8 +537,15 @@ class ReplDriver(settings: Array[String], } } + // TODO: no idea how to access and reload the class paths + val newClassPath = state.context.platform.classPath(using state.context).asURLs :+ f.toURI.toURL + println(s"new class path=${newClassPath.mkString(", ")}") val clsl = rendering.classLoader()(using state.context) + val newClsl = fromURLsParallelCapable(newClassPath, clsl) + println(s"newClsl getResource=${newClsl.getURLs.toList}") + newClsl.asContext(state.context) +// Scala 2: // def alreadyDefined(clsName: String) = classLoader.tryToLoadClass(clsName).isDefined // val existingClass = entries.filter(_.ext.isClass).map(classNameOf).find(alreadyDefined) From 597d6b115a293291fa13cef5d027515710ba66b3 Mon Sep 17 00:00:00 2001 From: aherlihy Date: Fri, 10 Jan 2025 17:41:03 -0500 Subject: [PATCH 167/505] Add updateClassPath + reset rootctx [Cherry-picked b8034c231de2e95fa4e0c9dfb08d991af05d30d4] --- .../tools/dotc/config/JavaPlatform.scala | 6 +++ .../dotty/tools/dotc/config/Platform.scala | 1 + .../src/dotty/tools/repl/ReplDriver.scala | 53 +++++++++++-------- 3 files changed, 39 insertions(+), 21 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala b/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala index 884e40e97d96..549398e0f7cf 100644 --- a/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala +++ b/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala @@ -27,6 +27,12 @@ class JavaPlatform extends Platform { case _ => false }) + def addToClassPath(cPath: ClassPath): Unit = currentClassPath.get match { + case AggregateClassPath(entries) => + currentClassPath = Some(AggregateClassPath(entries :+ cPath)) + case cp: ClassPath => + currentClassPath = Some(AggregateClassPath(cp :: cPath :: Nil)) + } /** Update classpath with a substituted subentry */ def updateClassPath(subst: Map[ClassPath, ClassPath]): Unit = currentClassPath.get match { case AggregateClassPath(entries) => diff --git a/compiler/src/dotty/tools/dotc/config/Platform.scala b/compiler/src/dotty/tools/dotc/config/Platform.scala index db05996d98fd..48ee781ccb2a 100644 --- a/compiler/src/dotty/tools/dotc/config/Platform.scala +++ b/compiler/src/dotty/tools/dotc/config/Platform.scala @@ -20,6 +20,7 @@ abstract class Platform { /** Update classpath with a substitution that maps entries to entries */ def updateClassPath(subst: Map[ClassPath, ClassPath]): Unit + def addToClassPath(cPath: ClassPath): Unit /** Any platform-specific phases. */ //def platformPhases: List[SubComponent] diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 1c81db694406..4c6fb3851089 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -1,17 +1,16 @@ package dotty.tools.repl import scala.language.unsafeNulls - -import java.io.{File => JFile, PrintStream} +import java.io.{PrintStream, File as JFile} import java.nio.charset.StandardCharsets - import dotty.tools.dotc.ast.Trees.* import dotty.tools.dotc.ast.{tpd, untpd} +import dotty.tools.dotc.classpath.{AggregateClassPath, ClassPathFactory, ZipAndJarClassPathFactory} import dotty.tools.dotc.config.CommandLineParser.tokenize import dotty.tools.dotc.config.Properties.{javaVersion, javaVmName, simpleVersionString} import dotty.tools.dotc.core.Contexts.* import dotty.tools.dotc.core.Decorators.* -import dotty.tools.dotc.core.Phases.{unfusedPhases, typerPhase} +import dotty.tools.dotc.core.Phases.{typerPhase, unfusedPhases} import dotty.tools.dotc.core.Denotations.Denotation import dotty.tools.dotc.core.Flags.* import dotty.tools.dotc.core.Mode @@ -537,24 +536,36 @@ class ReplDriver(settings: Array[String], } } - // TODO: no idea how to access and reload the class paths - val newClassPath = state.context.platform.classPath(using state.context).asURLs :+ f.toURI.toURL - println(s"new class path=${newClassPath.mkString(", ")}") - val clsl = rendering.classLoader()(using state.context) - val newClsl = fromURLsParallelCapable(newClassPath, clsl) - println(s"newClsl getResource=${newClsl.getURLs.toList}") - newClsl.asContext(state.context) - -// Scala 2: -// def alreadyDefined(clsName: String) = classLoader.tryToLoadClass(clsName).isDefined -// val existingClass = entries.filter(_.ext.isClass).map(classNameOf).find(alreadyDefined) - -// if (existingClass.nonEmpty) out.println(s"The path '$f' cannot be loaded, it contains a classfile that already exists on the classpath: ${existingClass.get}") -// else { -// intp.addUrlsToClassPath(f.toURI.toURL) + def alreadyDefined(clsName: String) = state.context.platform.classPath(using state.context).findClassFile(clsName).isDefined + val existingClass = entries.filter(_.ext.isClass).map(classNameOf).find(alreadyDefined) + if (existingClass.nonEmpty) + out.println(s"The path '$f' cannot be loaded, it contains a classfile that already exists on the classpath: ${existingClass.get}") + else +// val cp = state.context.platform.classPath(using state.context).asClassPathString +// println(s"CURRENT CP STRING: $cp") +// val newCP = s"$cp${JFile.pathSeparator}$path" +// println(s"UPDATED CP: $newCP") + + // add to compiler class path + println(s"INIT state classPath = ${state.context.platform.classPath(using state.context).asClassPathString}") + val cpCP = ClassPathFactory.newClassPath(jarFile)(using state.context) + state.context.platform.addToClassPath(cpCP) + println(s"classPath after add = ${state.context.platform.classPath(using state.context).asClassPathString}") + + // create initial context + rootCtx = setupRootCtx(Array(), rootCtx) + state.copy(context = rootCtx) + + + // new class loader +// val newClassPath = state.context.platform.classPath(using state.context).asURLs :+ f.toURI.toURL +// val oldCL = rendering.classLoader()(using state.context) +// val newCL = fromURLsParallelCapable(newClassPath, oldCL) +// println(s"new CL class path = ${newCL.getURLs.toList}") +// println(s"\nclass name = ${cpCP.className}") +// rendering.myClassLoader = new AbstractFileClassLoader(state.context.settings.outputDir.default, newCL) // out.println(s"Added '$path' to classpath.") -// out.println("Added '%s'. Your new classpath is:\n\"%s\"".format(f.path, intp.classPathString)) -// } + println(s"after setupRootCtx classPath = ${state.context.platform.classPath(using state.context).asClassPathString}") state case KindOf(expr) => From b024bd6b8e73c4cd9c42616d2fa4020829850700 Mon Sep 17 00:00:00 2001 From: aherlihy Date: Fri, 10 Jan 2025 17:58:38 -0500 Subject: [PATCH 168/505] updated state with classpath [Cherry-picked 800356babcdeaf99ff599a1f1c021417cfdfb517] --- .../src/dotty/tools/repl/ReplDriver.scala | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 4c6fb3851089..9b16b5629a73 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -540,21 +540,23 @@ class ReplDriver(settings: Array[String], val existingClass = entries.filter(_.ext.isClass).map(classNameOf).find(alreadyDefined) if (existingClass.nonEmpty) out.println(s"The path '$f' cannot be loaded, it contains a classfile that already exists on the classpath: ${existingClass.get}") + state else -// val cp = state.context.platform.classPath(using state.context).asClassPathString + val cp = state.context.platform.classPath(using state.context).asClassPathString // println(s"CURRENT CP STRING: $cp") -// val newCP = s"$cp${JFile.pathSeparator}$path" -// println(s"UPDATED CP: $newCP") + val newCP = s"$cp${JFile.pathSeparator}$path" + println(s"UPDATED CP: $newCP") // add to compiler class path - println(s"INIT state classPath = ${state.context.platform.classPath(using state.context).asClassPathString}") - val cpCP = ClassPathFactory.newClassPath(jarFile)(using state.context) - state.context.platform.addToClassPath(cpCP) - println(s"classPath after add = ${state.context.platform.classPath(using state.context).asClassPathString}") +// println(s"INIT state classPath = ${state.context.platform.classPath(using state.context).asClassPathString}") +// val cpCP = ClassPathFactory.newClassPath(jarFile)(using state.context) +// state.context.platform.addToClassPath(cpCP) +// println(s"classPath after add = ${state.context.platform.classPath(using state.context).asClassPathString}") - // create initial context - rootCtx = setupRootCtx(Array(), rootCtx) - state.copy(context = rootCtx) + // recreate initial context + rootCtx = setupRootCtx(Array(), rootCtx.fresh.setSetting(rootCtx.settings.classpath, newCP)) + val s = state.copy(context = rootCtx) + println(s"after setupRootCtx classPath = ${s.context.platform.classPath(using s.context).asClassPathString}") // new class loader @@ -565,13 +567,11 @@ class ReplDriver(settings: Array[String], // println(s"\nclass name = ${cpCP.className}") // rendering.myClassLoader = new AbstractFileClassLoader(state.context.settings.outputDir.default, newCL) // out.println(s"Added '$path' to classpath.") - println(s"after setupRootCtx classPath = ${state.context.platform.classPath(using state.context).asClassPathString}") - state + s case KindOf(expr) => out.println(s"""The :kind command is not currently supported.""") state - case TypeOf(expr) => expr match { case "" => out.println(s":type ") From 7d2774d2cd82308227a1aed271e0da8bc0ee9c3f Mon Sep 17 00:00:00 2001 From: aherlihy Date: Mon, 13 Jan 2025 10:37:36 -0500 Subject: [PATCH 169/505] fix test order [Cherry-picked f79588b5e55a499ab5c9b50d6137605c5fa4d914] --- compiler/test/dotty/tools/repl/TabcompleteTests.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/test/dotty/tools/repl/TabcompleteTests.scala b/compiler/test/dotty/tools/repl/TabcompleteTests.scala index 3cfe976d8169..75ecb03b95d7 100644 --- a/compiler/test/dotty/tools/repl/TabcompleteTests.scala +++ b/compiler/test/dotty/tools/repl/TabcompleteTests.scala @@ -218,8 +218,8 @@ class TabcompleteTests extends ReplTest { ":imports", ":kind", ":load", - ":require", ":quit", + ":require", ":reset", ":settings", ":sh", From fb1187dc0b87a7465e2d74c8c488e457745a22b1 Mon Sep 17 00:00:00 2001 From: aherlihy Date: Mon, 13 Jan 2025 11:35:40 -0500 Subject: [PATCH 170/505] working but state lost [Cherry-picked 0fad93965cce76c2c54367430a37ca631ad94432] --- compiler/src/dotty/tools/repl/ReplDriver.scala | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 9b16b5629a73..3b6180cecd1b 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -554,18 +554,14 @@ class ReplDriver(settings: Array[String], // println(s"classPath after add = ${state.context.platform.classPath(using state.context).asClassPathString}") // recreate initial context - rootCtx = setupRootCtx(Array(), rootCtx.fresh.setSetting(rootCtx.settings.classpath, newCP)) + resetToInitial(List("-classpath", newCP)) +// rootCtx = setupRootCtx(Array(), rootCtx.fresh.setSetting(rootCtx.settings.classpath, newCP)) val s = state.copy(context = rootCtx) - println(s"after setupRootCtx classPath = ${s.context.platform.classPath(using s.context).asClassPathString}") - // new class loader -// val newClassPath = state.context.platform.classPath(using state.context).asURLs :+ f.toURI.toURL -// val oldCL = rendering.classLoader()(using state.context) -// val newCL = fromURLsParallelCapable(newClassPath, oldCL) -// println(s"new CL class path = ${newCL.getURLs.toList}") -// println(s"\nclass name = ${cpCP.className}") -// rendering.myClassLoader = new AbstractFileClassLoader(state.context.settings.outputDir.default, newCL) + val oldCL = rendering.classLoader()(using state.context) + val newCL = fromURLsParallelCapable(s.context.platform.classPath(using s.context).asURLs, oldCL) + rendering.myClassLoader = new AbstractFileClassLoader(state.context.settings.outputDir.default, newCL) // out.println(s"Added '$path' to classpath.") s From 098f2dd00bd6134409815561c27bd9505d78bdf1 Mon Sep 17 00:00:00 2001 From: aherlihy Date: Wed, 15 Jan 2025 15:36:31 -0500 Subject: [PATCH 171/505] Clean up impl --- .../dotc/classpath/AggregateClassPath.scala | 7 ++- .../tools/dotc/config/JavaPlatform.scala | 4 +- .../dotty/tools/dotc/config/Platform.scala | 6 ++- .../src/dotty/tools/dotc/core/Contexts.scala | 6 ++- .../dotty/tools/dotc/core/Definitions.scala | 2 +- .../src/dotty/tools/repl/ReplDriver.scala | 54 ++++++++++--------- 6 files changed, 46 insertions(+), 33 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/classpath/AggregateClassPath.scala b/compiler/src/dotty/tools/dotc/classpath/AggregateClassPath.scala index 51b261583feb..699e2f438e4e 100644 --- a/compiler/src/dotty/tools/dotc/classpath/AggregateClassPath.scala +++ b/compiler/src/dotty/tools/dotc/classpath/AggregateClassPath.scala @@ -51,8 +51,11 @@ case class AggregateClassPath(aggregates: Seq[ClassPath]) extends ClassPath { case (_, s) => s } } - - override def asURLs: Seq[URL] = aggregates.flatMap(_.asURLs) + override def asURLs: Seq[URL] = + aggregates.flatMap { + case v: VirtualDirectoryClassPath => Seq() + case a => a.asURLs + } override def asClassPathStrings: Seq[String] = aggregates.map(_.asClassPathString).distinct diff --git a/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala b/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala index 549398e0f7cf..80deb207be0c 100644 --- a/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala +++ b/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala @@ -27,14 +27,14 @@ class JavaPlatform extends Platform { case _ => false }) - def addToClassPath(cPath: ClassPath): Unit = currentClassPath.get match { + def addToClassPath(cPath: ClassPath)(using Context): Unit = classPath match { case AggregateClassPath(entries) => currentClassPath = Some(AggregateClassPath(entries :+ cPath)) case cp: ClassPath => currentClassPath = Some(AggregateClassPath(cp :: cPath :: Nil)) } /** Update classpath with a substituted subentry */ - def updateClassPath(subst: Map[ClassPath, ClassPath]): Unit = currentClassPath.get match { + def updateClassPath(subst: Map[ClassPath, ClassPath])(using Context): Unit = classPath match { case AggregateClassPath(entries) => currentClassPath = Some(AggregateClassPath(entries map (e => subst.getOrElse(e, e)))) case cp: ClassPath => diff --git a/compiler/src/dotty/tools/dotc/config/Platform.scala b/compiler/src/dotty/tools/dotc/config/Platform.scala index 48ee781ccb2a..6c3542bc2e6c 100644 --- a/compiler/src/dotty/tools/dotc/config/Platform.scala +++ b/compiler/src/dotty/tools/dotc/config/Platform.scala @@ -19,8 +19,10 @@ abstract class Platform { def classPath(using Context): ClassPath /** Update classpath with a substitution that maps entries to entries */ - def updateClassPath(subst: Map[ClassPath, ClassPath]): Unit - def addToClassPath(cPath: ClassPath): Unit + def updateClassPath(subst: Map[ClassPath, ClassPath])(using Context): Unit + + /** Add new entry to classpath */ + def addToClassPath(cPath: ClassPath)(using Context): Unit /** Any platform-specific phases. */ //def platformPhases: List[SubComponent] diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index 8c09a3f24fa0..075de9e934fe 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -35,6 +35,7 @@ import scala.annotation.internal.sharable import DenotTransformers.DenotTransformer import dotty.tools.dotc.profile.Profiler import dotty.tools.dotc.sbt.interfaces.{IncrementalCallback, ProgressCallback} +import dotty.tools.dotc.classpath.ClassPathFactory import util.Property.Key import util.Store import plugins.* @@ -897,8 +898,11 @@ object Contexts { /** Initializes the `ContextBase` with a starting context. * This initializes the `platform` and the `definitions`. */ - def initialize()(using Context): Unit = { + def initialize(previousOutputDir: Option[AbstractFile] = None)(using Context): Unit = { _platform = newPlatform + previousOutputDir.foreach(cp => + _platform.nn.addToClassPath(ClassPathFactory.newClassPath(cp)) + ) definitions.init() } diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index da57315e15ff..5c7d3786bd7e 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -2150,7 +2150,7 @@ class Definitions { private var isInitialized = false - def init()(using Context): Unit = { + def init(require: Boolean = false)(using Context): Unit = { this.initCtx = ctx if (!isInitialized) { // force initialization of every symbol that is synthesized or hijacked by the compiler diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 3b6180cecd1b..02ff35523637 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -1,16 +1,16 @@ package dotty.tools.repl import scala.language.unsafeNulls -import java.io.{PrintStream, File as JFile} +import java.io.{File => JFile, PrintStream} import java.nio.charset.StandardCharsets import dotty.tools.dotc.ast.Trees.* import dotty.tools.dotc.ast.{tpd, untpd} -import dotty.tools.dotc.classpath.{AggregateClassPath, ClassPathFactory, ZipAndJarClassPathFactory} +import dotty.tools.dotc.classpath.ClassPathFactory import dotty.tools.dotc.config.CommandLineParser.tokenize import dotty.tools.dotc.config.Properties.{javaVersion, javaVmName, simpleVersionString} import dotty.tools.dotc.core.Contexts.* import dotty.tools.dotc.core.Decorators.* -import dotty.tools.dotc.core.Phases.{typerPhase, unfusedPhases} +import dotty.tools.dotc.core.Phases.{unfusedPhases, typerPhase} import dotty.tools.dotc.core.Denotations.Denotation import dotty.tools.dotc.core.Flags.* import dotty.tools.dotc.core.Mode @@ -88,12 +88,12 @@ class ReplDriver(settings: Array[String], setupRootCtx(this.settings ++ settings, rootCtx) } - private def setupRootCtx(settings: Array[String], rootCtx: Context) = { + private def setupRootCtx(settings: Array[String], rootCtx: Context, previousOutputDir: Option[AbstractFile] = None) = { setup(settings, rootCtx) match case Some((files, ictx)) => inContext(ictx) { shouldStart = true if files.nonEmpty then out.println(i"Ignoring spurious arguments: $files%, %") - ictx.base.initialize() + ictx.base.initialize(previousOutputDir) ictx } case None => @@ -526,43 +526,47 @@ class ReplDriver(settings: Array[String], val entries = flatten(jarFile) - def classNameOf(classFile: AbstractFile): String = { + def tryClassLoad(classFile: AbstractFile): Option[String] = { val input = classFile.input try { val reader = new ClassReader(input) - reader.getClassName.replace('/', '.') - } finally { + val clsName = reader.getClassName.replace('/', '.') + rendering.myClassLoader.loadClass(clsName) + Some(clsName) + } catch + case _: ClassNotFoundException => None + finally { input.close() } } - def alreadyDefined(clsName: String) = state.context.platform.classPath(using state.context).findClassFile(clsName).isDefined - val existingClass = entries.filter(_.ext.isClass).map(classNameOf).find(alreadyDefined) + val existingClass = entries.filter(_.ext.isClass).find(tryClassLoad(_).isDefined) if (existingClass.nonEmpty) out.println(s"The path '$f' cannot be loaded, it contains a classfile that already exists on the classpath: ${existingClass.get}") state else val cp = state.context.platform.classPath(using state.context).asClassPathString -// println(s"CURRENT CP STRING: $cp") val newCP = s"$cp${JFile.pathSeparator}$path" - println(s"UPDATED CP: $newCP") // add to compiler class path -// println(s"INIT state classPath = ${state.context.platform.classPath(using state.context).asClassPathString}") -// val cpCP = ClassPathFactory.newClassPath(jarFile)(using state.context) -// state.context.platform.addToClassPath(cpCP) -// println(s"classPath after add = ${state.context.platform.classPath(using state.context).asClassPathString}") - - // recreate initial context - resetToInitial(List("-classpath", newCP)) -// rootCtx = setupRootCtx(Array(), rootCtx.fresh.setSetting(rootCtx.settings.classpath, newCP)) + val prevOutputDir = rootCtx.settings.outputDir.valueIn(rootCtx.settingsState) + val ctxToUse = initCtx.fresh.setSetting(rootCtx.settings.classpath, newCP) + rootCtx = setupRootCtx( + Array(), + ctxToUse, + previousOutputDir = Some(prevOutputDir) + ) val s = state.copy(context = rootCtx) - // new class loader - val oldCL = rendering.classLoader()(using state.context) - val newCL = fromURLsParallelCapable(s.context.platform.classPath(using s.context).asURLs, oldCL) - rendering.myClassLoader = new AbstractFileClassLoader(state.context.settings.outputDir.default, newCL) -// out.println(s"Added '$path' to classpath.") + // new class loader with previous output dir and specified jar + val prevClassLoader = rendering.classLoader()(using state.context) + val jarClassLoader = fromURLsParallelCapable( + ClassPathFactory.newClassPath(jarFile)(using rootCtx).asURLs, prevClassLoader) + val replOutputClassLoader = new AbstractFileClassLoader( + prevOutputDir, jarClassLoader) + rendering.myClassLoader = new AbstractFileClassLoader( + rootCtx.settings.outputDir.valueIn(rootCtx.settingsState), replOutputClassLoader) + out.println(s"Added '$path' to classpath.") s case KindOf(expr) => From 57f6fb0c64c3e1117981aa9df2ac0fb5dc8a7134 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Fri, 25 Apr 2025 08:35:34 +0200 Subject: [PATCH 172/505] Clean up impl [Cherry-picked 7b0ba9f4df0ff9c84deeb854876a8b15cb4dbb5f][modified] From 563e169f89c11a195a6f3c5eb01c2ffd64391996 Mon Sep 17 00:00:00 2001 From: aherlihy Date: Wed, 15 Jan 2025 16:49:36 -0500 Subject: [PATCH 173/505] further cleanup, reuse dir (bug w double import) [Cherry-picked 1ac09e6276fe8fd003b5fa55dd3f754da44b6457] --- .../src/dotty/tools/repl/ReplDriver.scala | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 02ff35523637..30e53f67c4cc 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -514,9 +514,8 @@ class ReplDriver(settings: Array[String], } case Require(path) => - val f = new JFile(path) val jarFile = AbstractFile.getDirectory(path) - if (!f.exists || jarFile == null) + if (jarFile == null) out.println(s"""Cannot add "$path" to classpath.""") state else @@ -542,15 +541,17 @@ class ReplDriver(settings: Array[String], val existingClass = entries.filter(_.ext.isClass).find(tryClassLoad(_).isDefined) if (existingClass.nonEmpty) - out.println(s"The path '$f' cannot be loaded, it contains a classfile that already exists on the classpath: ${existingClass.get}") + out.println(s"The path '$path' cannot be loaded, it contains a classfile that already exists on the classpath: ${existingClass.get}") state else - val cp = state.context.platform.classPath(using state.context).asClassPathString - val newCP = s"$cp${JFile.pathSeparator}$path" + val prevClassPath = state.context.platform.classPath(using state.context).asClassPathString + val newClassPath = s"$prevClassPath${JFile.pathSeparator}$path" // add to compiler class path val prevOutputDir = rootCtx.settings.outputDir.valueIn(rootCtx.settingsState) - val ctxToUse = initCtx.fresh.setSetting(rootCtx.settings.classpath, newCP) + val ctxToUse = initCtx.fresh + .setSetting(rootCtx.settings.classpath, newClassPath) + .setSetting(rootCtx.settings.outputDir, prevOutputDir) // reuse virtual output directory rootCtx = setupRootCtx( Array(), ctxToUse, @@ -562,10 +563,11 @@ class ReplDriver(settings: Array[String], val prevClassLoader = rendering.classLoader()(using state.context) val jarClassLoader = fromURLsParallelCapable( ClassPathFactory.newClassPath(jarFile)(using rootCtx).asURLs, prevClassLoader) - val replOutputClassLoader = new AbstractFileClassLoader( - prevOutputDir, jarClassLoader) +// val replOutputClassLoader = new AbstractFileClassLoader( +// prevOutputDir, jarClassLoader) rendering.myClassLoader = new AbstractFileClassLoader( - rootCtx.settings.outputDir.valueIn(rootCtx.settingsState), replOutputClassLoader) + rootCtx.settings.outputDir.valueIn(rootCtx.settingsState), jarClassLoader) //replOutputClassLoader) + println(s"new classpath: ${s.context.platform.classPath(using s.context)}") out.println(s"Added '$path' to classpath.") s From f8e599054898e7ae57f5570904f8b3166862c91e Mon Sep 17 00:00:00 2001 From: aherlihy Date: Wed, 15 Jan 2025 17:36:52 -0500 Subject: [PATCH 174/505] Add simple tests [Cherry-picked 2babf5ca588ce12bb203d8a51a8bb1fc6b104874] --- compiler/src/dotty/tools/repl/ReplDriver.scala | 5 +---- compiler/test-resources/repl/require-command | 13 +++++++++++++ compiler/test-resources/repl/require-errors | 8 ++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 compiler/test-resources/repl/require-command create mode 100644 compiler/test-resources/repl/require-errors diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 30e53f67c4cc..136b019a33ea 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -563,11 +563,8 @@ class ReplDriver(settings: Array[String], val prevClassLoader = rendering.classLoader()(using state.context) val jarClassLoader = fromURLsParallelCapable( ClassPathFactory.newClassPath(jarFile)(using rootCtx).asURLs, prevClassLoader) -// val replOutputClassLoader = new AbstractFileClassLoader( -// prevOutputDir, jarClassLoader) rendering.myClassLoader = new AbstractFileClassLoader( - rootCtx.settings.outputDir.valueIn(rootCtx.settingsState), jarClassLoader) //replOutputClassLoader) - println(s"new classpath: ${s.context.platform.classPath(using s.context)}") + rootCtx.settings.outputDir.valueIn(rootCtx.settingsState), jarClassLoader) out.println(s"Added '$path' to classpath.") s diff --git a/compiler/test-resources/repl/require-command b/compiler/test-resources/repl/require-command new file mode 100644 index 000000000000..1af49ccff6fb --- /dev/null +++ b/compiler/test-resources/repl/require-command @@ -0,0 +1,13 @@ +scala> val z = 1 +val z: Int = 1 + +scala>:require sbt-test/source-dependencies/canon/actual/a.jar +Added 'sbt-test/source-dependencies/canon/actual/a.jar' to classpath. + +scala> import A.x + +scala> x +val res0: Int = 3 + +scala> z +val res1: Int = 1 diff --git a/compiler/test-resources/repl/require-errors b/compiler/test-resources/repl/require-errors new file mode 100644 index 000000000000..8e26c673f9b3 --- /dev/null +++ b/compiler/test-resources/repl/require-errors @@ -0,0 +1,8 @@ +scala>:require path/does/not/exist +Cannot add "path/does/not/exist" to classpath. + +scala>:require sbt-test/source-dependencies/canon/actual/a.jar +Added 'sbt-test/source-dependencies/canon/actual/a.jar' to classpath. + +scala>:require sbt-test/source-dependencies/canon/actual/a.jar +The path 'sbt-test/source-dependencies/canon/actual/a.jar' cannot be loaded, it contains a classfile that already exists on the classpath: sbt-test/source-dependencies/canon/actual/a.jar(A.class) From 585b78aa0446222d8c0cafc95502156004893c9e Mon Sep 17 00:00:00 2001 From: aherlihy Date: Wed, 15 Jan 2025 22:13:47 -0500 Subject: [PATCH 175/505] Handle out of sync imports after require + tests [Cherry-picked 4d1e2b02d0b66fc397b1dd2ddafa55c39f0e0295] --- .../src/dotty/tools/repl/ReplCompiler.scala | 6 +++- compiler/test-resources/jars/MyLibrary.scala | 10 ++++++ compiler/test-resources/jars/MyLibrary2.scala | 10 ++++++ compiler/test-resources/jars/mylibrary.jar | Bin 0 -> 3399 bytes compiler/test-resources/jars/mylibrary2.jar | Bin 0 -> 3435 bytes compiler/test-resources/repl/require-multiple | 32 ++++++++++++++++++ 6 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 compiler/test-resources/jars/MyLibrary.scala create mode 100644 compiler/test-resources/jars/MyLibrary2.scala create mode 100644 compiler/test-resources/jars/mylibrary.jar create mode 100644 compiler/test-resources/jars/mylibrary2.jar create mode 100644 compiler/test-resources/repl/require-multiple diff --git a/compiler/src/dotty/tools/repl/ReplCompiler.scala b/compiler/src/dotty/tools/repl/ReplCompiler.scala index e34bb229a727..1ec2d230f7e9 100644 --- a/compiler/src/dotty/tools/repl/ReplCompiler.scala +++ b/compiler/src/dotty/tools/repl/ReplCompiler.scala @@ -46,7 +46,11 @@ class ReplCompiler extends Compiler: /** Import previous runs and user defined imports */ override protected def rootContext(using Context): Context = { def importContext(imp: tpd.Import)(using Context) = - ctx.importContext(imp, imp.symbol) + // TODO: only when context has changed? + val typer = ctx.typer + typer.index(imp) + val imp2 = typer.typed(imp).asInstanceOf[tpd.Import] + ctx.importContext(imp2, imp2.symbol) def importPreviousRun(id: Int)(using Context) = { // we first import the wrapper object id diff --git a/compiler/test-resources/jars/MyLibrary.scala b/compiler/test-resources/jars/MyLibrary.scala new file mode 100644 index 000000000000..8dda1938608a --- /dev/null +++ b/compiler/test-resources/jars/MyLibrary.scala @@ -0,0 +1,10 @@ +// MyLibrary.scala +package mylibrary + +object Utils: + def greet(name: String): String = s"Hello, $name!" + +class Calculator: + def add(x: Int, y: Int): Int = x + y + def subtract(x: Int, y: Int): Int = x - y + diff --git a/compiler/test-resources/jars/MyLibrary2.scala b/compiler/test-resources/jars/MyLibrary2.scala new file mode 100644 index 000000000000..2fdfa6c09b5d --- /dev/null +++ b/compiler/test-resources/jars/MyLibrary2.scala @@ -0,0 +1,10 @@ +// MyLibrary2.scala +package mylibrary2 + +object Utils2: + def greet(name: String): String = s"Hello, $name!" + +class Calculator2: + def add(x: Int, y: Int): Int = x + y + def subtract(x: Int, y: Int): Int = x - y + diff --git a/compiler/test-resources/jars/mylibrary.jar b/compiler/test-resources/jars/mylibrary.jar new file mode 100644 index 0000000000000000000000000000000000000000..5378fdcc0f7209b1d0ad4a34dd71e19120bcb74d GIT binary patch literal 3399 zcmbVPc{r5a8y+TOEJ@axZ|or^V_yr!Fky@=i9{J`vBxkaQq!QO#88QB!$_7$MT@P* zzBLn}1sO6SpOOiM_|4RJMSaU3zvsQ)>pJhbp65Q#Ip;plxnD;#aGeAI3 z)|dcb9ROp!+X7+hfYMrS2LONoM>Ic}>%se%o8!L*OK?1X24gH7Y*E%OyEQQ=Hm0+~ z9*xlKT8~D+>79&w&e}bCOjekt9Y(_z(-l#?PB3i}I-b7e=oe`f)v{A%e_Z+-(se_iB5x6fm2SEUUlUMU^6X5g$f+7R`e8R9{ky@*{{_gk3FMddD z;K7JMYXWjRXKH}LhyBkpx^>e>4M_7_;LEUo#!lb5ck1sK0E4h%+Pio8A`jOTvOc<0Zkuj z+o^3ckr43u1Pl2YSn!wV=%CDf$QL38t-?+CK!?To&4%+P$b#WZwbN-9Wxb1hz7$rj zLI))l7*g-3BVB5o7xTeb*uS*5_yOc4;#->er$3eNTGFP-_SXq-yFH%6s4BlSRrB!!TQ&*=Na*=FA=7=Zug{pKf}yOAo~yz+V(qc*eRI7X1A&HFgX!<@ zy^1Z}u`7bl+DEL9G?riCX@8^FdX8Rm>ciSvdXOp9cY zI^?;OvdGzZ`T!3AV8G$k|FKQsSX_AIp+rW&b8kosdz87tY#Y46m(Dz7yNS=@lk}dD z`V$#^Z8qYq8+2~gMGhH-bT<}E8X9?3SGsz36#HdVNZk6 z=c-GA@+olL-HaV&hkysVF@skLrFqrhG(zV#C9L9fz^p4K!n&R+n5$F1&jgg~lFwtk zWsB$l@MKrG;MtFRB(6&@U@5sh=v+Dk z^BD{`=(mcukuw)-qf1R+516zTcyrtFb$=XPa%INp(~Q%}$tu=(91$4W>#wi>JYrhQ z)Qxw6`1x^Tn{qHBD!KlK2E~aWv2Y#q3#%+(5<9CR`NAlv#%zv z`kB~ja*}wd?Ux-fTD6zA*Lbq;U&$KC{)j;9`QiPvm(t6Qhb|g?_#p2s6ZE7dZGE<2 z&R5dL?SXUWmP;^L)y|B|SoYIs&80SxR|?DV$JMjrL+>E zkCMtt_uSjFgqYkweOSZPkpZLE}6OQAJFvRAEZFKs8 z$=E;?V=(7&-3q|5$t8ZtJI{9~&MY*Ew+N*ol#q9G33yy`ej)fC4qiowQ*Q8qT&?RD z^9WPf&Q27Q>K1;~oG(}O=cOvoP*6!%bm;EWdwtY;#$0+Jnp5aqAO<9b)qV#E6Ebu@ z263j5WORJzs^L~IZJvaZEez4sCBpQb2;e6NVabnz#YLV)3~BU21{PW-7e$Z(KNy~G zw#&RGYcsU1XZa>6ZW1+eww^FTbwU*TwV^f|LAp;Ntaju{6H0fWZyzXGg6653np0k< zzPp{BbmP51&@et_i6L6Pq-s}r_@LyZZ+}4UmB;r|X`uARbI9RY2!3Tt=&k*@V;eG1 zAI*XL7!*r9C?+=DNJ9!&en}Sj%7DGFZzq3D($@Cg8=K!G^2_E9WemeAb~(u7!cys> z+C!o=($Kci>(SuY0>W#=>08w!SM}#7Qqx7`x~*I&<`Z6qn^aw#C8&=HN*l&UyRUT_ z)fzOhZdcff3MkTc$alTB0(c5c>>Z`I!D0;=^}?h%iLW7Q5COb}5{4Y$o*>|=+)!wS zyyInKe`kp$uRdk0(tx=o+ODQ=OH=kr$5whh)N2~FoDgOOofO(vk%c#Tg2Hc$SU6nBp?1i#sFJC)&a!+bGBihshEZ zf#N_RAXuAs7EsCS$D^=oof;jSZ(^u3?H_cIIRx0#(5V1cPKUTdW6x9okOi(I2`{s5 zLaX{S?ML*Dw82D)9~bW#6fIzivl=GXF%MlYjx$RdY>FFZPnegMlUs)(#yq+5Tq z=S!$-MQqGGk#Y#dr=hH9prLaM;%J~91xZXk>4)j%^@kTiRUzUh#E3MX;LN^2{>}`l zxUy>3^^CbOs3X-|cu~oQbdyegq@^teRT7YD0jHhv3_Cx-hbEhlNa7wHk`(AP?n=Z1)PnOy)To4a_dbuC-cW- zdzuw$J>Ji&2cNEySYH@XUM8N((yAn$Ax3S*1rzh&8R5#a87F(WVZ@w!6LE2vg+Z zcLw{fy+alUMHNU+-AV2*K9xgP_NoF#)_qJSfZbJR^eBfa;>|ACoxS-gUqtrY!mGeNg}2{Sv1#t% zyRPuLlbQSSH#ZZV8Z*{+MM8`!I(>sv7pA`}5*}U& zz^@va)BWAJ8u?fIDSEkz*%AF~=vv*%RmiJm#%cZxU89$|2!eor*SD((G){A^+Fc!) zt9RE*EUw;NwFyphHSTxyyLJX#oV6G9uQ+7Rn*1Zq_mlrS&f3Duz0OzdI%h>!an@e$ zzhkT|M%=&s-@$k-BOFHWh`AIVvxM*MF*HC+ zJ!LaMOZ4^jSDVRD736&YXU2phAQUSYM z7rhs}8GhtonP2cyo7MyUrRTs30MPPE|7`#e+Fy5)o3ov_tv5+d`d6~QJ0i9_>e#xS zKIdjj^z@dKI_+lbiJ9SWPkY+st(SIE z1F!F>$#U_OFYb`wth+LTxlfVr(wp$|JiwX}2g}%lPl*pk)v3hw&>WQd7a`N(H(fTk z^Ccp)P;E@{o(ANKwr=b0AwyNlZKGNlzrcg3VEA&+X9><+?(Wd;FMW>(gO##eE}U7f zSF+vzWbi>SQkI3k-N#H-s<3pZX)Z@^{l)h=hvXx|yRt%6H5xNFH#iC zA?-1#xeJb6*ObnbQn=)l&527)bvi?WBRfm)DVbI4>|F(XJ8G93nCH{PKe+46LGsJzE$jb>H`5?uR2=l zTu7amUp?;pq=Fp4(UDYKKM}^7Hi{zekhVyKFTP`7KWQ<0L%%iTPKy5hHQh(3xo%;2xy}{;!wp(__u1s*9Bgua-r0UxVX^V4}5MM{tw4^j6=k&Pxmb(`wXlH6~(+} z`;yE?XbM^gXjWmutn$$d!a=ucwv$#6Uuo~33j(%%=N=_GyZOkWe(u^>GfPh{Egto@ zE0D1vq=ie_vuAc;m&=e}wWmUk7O-H2@335DGJL1dCI#o+6_E0fj7nT(+Aw{n)>F8b z0#nWy$+$n0?KfY)PF=a03+VQJ82=$Q+0D89u*ix^yo*WqNgHT}{I`VrQGS+nr znzgfS_r>VHatEX96Rmv>SRlC8=a?bvnSdv6qvVg*e(jl>Ej{?OB(2&UR*t|L1N-5V zVUv+e{17EBFBn(LO@s`2=ct74a74@5cx_dD5f$1ehGtr@`n<~%G9b-Uy0o15&Ej}O z=@ly>zt*y~oO~|66wts*T+Mfq{p-SnbW;`cOESfVu7o=YZRl|OV-U{xcapa`o!+0@ z-_f(zrFBZZ#GUkQFgo8{ARqlAc96r2S+XIgkWg0{&L;OU)};HDrLk?2;pArHCsnB5 z_Y@Vg3Kic#biqn|kUQA~rN$Hxm7y%j<#Rj4QfH*#)ntW$z*m7;r%DO+1&?7@md%#l zS9$*4Uqh3siC2R&GQmcheVotV=m;sWQ9M?4Uh-DlSi9zy{(eFhufQ;y^ehT4n~|6Y z+hpS*=_;p<$BaMvAX|R9Kqm$ZW&skezsz9tLX(RseYM6>H6&iq2*u8>ONXCfZ^I)| zS{^q0kjb3v1z(u!9hHniod3rxgzBoWUA*E)U~hpkkv`S6@~a;S4w z>-^SWFPGelcTON5c*&9#V8;<71!qjwDG4hAE`aDICub1ahNkgPH`9NW9N)i{+|P-xf*PZE2x?S#(*F&JRbt@bM2&FuCDqW^dDEy^3N z^FYVEV$U1w=9N}wz3q&U!c49gOkAu(4c7-sYG8o8GaJd~7-0Ft#=!MA=5@UY zp(~2*vMMMpEGXnumrYl5dvhy*F-B8evrLl!=;CIGl4o>|!$TVgW3W}_z#$oVFe6SB zXaU?Sgl?YrUjEAX)EfnzfYUX44G)1p+j!)Ullb$C*0OopjA;JnHvRWG`$5_0_(O)= zXL&m3b0Q<aS5Y1{1Bsy zTrpe}*5;U`d08Ud=s{8t@?4xnr# zgIe;_`=hapZEQg!!V_A#rF*1#TVfX_sn*jWm#&b!(vKUaJ^@hqQ*(p%w5(v=Uz1D% z2!v2nRObkDOm1H5L9y4Shm7y+rleU(2IC+HrJpj?vOZ($t=gEzm`DeYiB70sxc0b# zUK;Q42u%wUZ|u7bJJo)+A=GG7x!Lhjar53(ij`;L=(Br*(|DFD%gC%EYfp`})WNps z-bzDewcbv<^d#LK=Xr)%Z@L&wopV+qkKQ>$AZFp~*;IL!k?-zMN2Y4BS?kRm>=_|A ziLw)zq-+)k{@VACL=PMunmgNn?Z&jWxUv6S(X&2aP5)K=42yMg^d#cwR5T^%0rjZF z`9}s1VvbFXJgM4X`nD*KAtIizfXMaT!o)?Q$A0EyX zTt8XCy_qOWqhE2LHWtyzk_UD@a-T5v@6FyQjz*= UJUf8&-oUhHH*M@{^s5Nqf37t~djJ3c literal 0 HcmV?d00001 diff --git a/compiler/test-resources/repl/require-multiple b/compiler/test-resources/repl/require-multiple new file mode 100644 index 000000000000..34faa564d37d --- /dev/null +++ b/compiler/test-resources/repl/require-multiple @@ -0,0 +1,32 @@ +scala> val z = 1 +val z: Int = 1 + +scala>:require compiler/test-resources/jars/mylibrary.jar +Added 'compiler/test-resources/jars/mylibrary.jar' to classpath. + +scala> import mylibrary.Utils + +scala> Utils.greet("Alice") +val res0: String = Hello, Alice! + +scala>:require compiler/test-resources/jars/mylibrary2.jar +Added 'compiler/test-resources/jars/mylibrary2.jar' to classpath. + +scala> import mylibrary2.Utils2 + +scala> Utils2.greet("Alice") +val res1: String = Hello, Alice! + +scala> Utils.greet("Alice") +val res2: String = Hello, Alice! + +scala> import mylibrary.Utils.greet + +scala> greet("Tom") +val res3: String = Hello, Tom! + +scala> Utils.greet("Alice") +val res4: String = Hello, Alice! + +scala> z +val res5: Int = 1 From ab9475eea0ef91c13672d85019dc61fd5ae6ea19 Mon Sep 17 00:00:00 2001 From: aherlihy Date: Thu, 16 Jan 2025 13:05:05 -0500 Subject: [PATCH 176/505] slightly cleaner tests [Cherry-picked 78bf30b8a4449f31552f0d49109608242973a5f0] --- compiler/test-resources/jars/MyLibrary.scala | 10 ++++------ compiler/test-resources/jars/MyLibrary2.scala | 11 +++++------ compiler/test-resources/jars/mylibrary.jar | Bin 3399 -> 2309 bytes compiler/test-resources/jars/mylibrary2.jar | Bin 3435 -> 2336 bytes compiler/test-resources/repl/require-multiple | 2 +- 5 files changed, 10 insertions(+), 13 deletions(-) diff --git a/compiler/test-resources/jars/MyLibrary.scala b/compiler/test-resources/jars/MyLibrary.scala index 8dda1938608a..cc492696c139 100644 --- a/compiler/test-resources/jars/MyLibrary.scala +++ b/compiler/test-resources/jars/MyLibrary.scala @@ -1,10 +1,8 @@ -// MyLibrary.scala +/** + * JAR used for testing repl :require + * Generated using: mkdir out; scalac -d out MyLibrary.scala; jar cf mylibrary.jar -C out . + */ package mylibrary object Utils: def greet(name: String): String = s"Hello, $name!" - -class Calculator: - def add(x: Int, y: Int): Int = x + y - def subtract(x: Int, y: Int): Int = x - y - diff --git a/compiler/test-resources/jars/MyLibrary2.scala b/compiler/test-resources/jars/MyLibrary2.scala index 2fdfa6c09b5d..ca288fcfbf85 100644 --- a/compiler/test-resources/jars/MyLibrary2.scala +++ b/compiler/test-resources/jars/MyLibrary2.scala @@ -1,10 +1,9 @@ -// MyLibrary2.scala +/** + * JAR used for testing repl :require + * Generated using: mkdir out2; scalac -d out MyLibrary2.scala; jar cf mylibrary2.jar -C out2 . + */ package mylibrary2 object Utils2: - def greet(name: String): String = s"Hello, $name!" - -class Calculator2: - def add(x: Int, y: Int): Int = x + y - def subtract(x: Int, y: Int): Int = x - y + def greet(name: String): String = s"Greetings, $name!" diff --git a/compiler/test-resources/jars/mylibrary.jar b/compiler/test-resources/jars/mylibrary.jar index 5378fdcc0f7209b1d0ad4a34dd71e19120bcb74d..4537e10ee4910923d760abced82b45e96367d257 100644 GIT binary patch delta 1741 zcmY+Fc{CgN7RQ5(rHOs5T`cX(vjLFp&(x#xcFcTh7^Nfw2a0IC3_ zrKJJ6VdfNBTZscXpL!^x#s@;J1HuSFo%iPa8(97UB-Jf{y?5%Gj=u2QDOOnK`|Bw( zrJ=8lxs~%RWAvi4N`w^0;kc^?9_a(@q0!MPo5iU_{`B3)J$nGuz=f>9U#hPlV;nXL zAPth=fXJ0~e@lE;mG4e|gojR0GL5)c?c$1A1^;Mc$4#1&+8B6zqTbefT#L}rH4pY_ z+MTc8YUj*(FJAaj!*q4T3BlJW>| zYvkNRcD6^=&AX{hlgBBgUe>&)TBnp_+VXT<#^IY= z0d7(u*|x(zIQ<#9#FG`XOp#XXIZwTqXxiv~OtVQPwKe7m{EGrX#zO+HDMCHqeH*^^ zT-H*@zM5F;lr;9A2!wlW^>GA2!d3U#P@P%TF9|=BM=pg^^_8&V7?EPrno7#IFo*ON zoA~r+3x0Hcfwtji*)j@7-6$e0kULLCAuRH3mESOfvE;XAd*_y(qAjNSk5rJIOI6&* zie-G5Go`S#giIGpl?O|oI>T(ZGY_kEkPCGkjOy{}TqYqR;d1N~#d7TnC+%T5vnZsL zbOQEf%L#D+fF}U}{NHd<)ul`bxcpwvJ|~5&y;NbQe+{I-DJP*7CLrA*&o^Yah~`qc z=+pQi|H7KWj~;R0zTUI)39oKK+&^K`V(5g>jUCHPR{S0yil|ocAyC7iZA?vc{8gx_ zQw9dAZeeACF;vX@HMB6*-6PBP^^x}_0&ncY!Mgq?*{v~#UWqIm|- z8MgA(rdNVXF9!Up;Jg4EP>goPI4R`Hm_)e0P$)6UV&8f{JS8+@<6(HH3H~tWNxkfIbQL53|rBB8)&f-^YV8dgbgdh?cDqI);dZu zn>dJ*k#Fk>c`NfyF`6kX`wp~RfF#}OBLbNj5z49yHbnAvd^D@P=i{%6PwP3GXsdD| zr`y?==J@K!vR{+F8bz;RU1WB2 zvew+SF}=#O$A+wynGcOifsXe|1@j6 z>Z_%kIP*FxuXtU}GQF1yL*iqE+br?%p3|)%u>Intig@_XC9#6ITKJ&p4pJhbp65Q#Ip;plxnD;#aGeAI3 z)|dcb9ROp!+X7+hfYMrS2LONoM>Ic}>%se%o8!L*OK?1X24gH7Y*E%OyEQQ=Hm0+~ z9*xlKT8~D+>79&w&e}bCOjekt9Y(_z(-l#?PB3i}I-b7e=oe`f)v{A%e_Z+-(se_iB5x6fm2SEUUlUMU^6X5g$f+7R`e8R9{ky@*{{_gk3FMddD z;K7JMYXWjRXKH}LhyBkpx^>e>4M_7_;LEUo#!lb5ck1sK0E4h%+Pio8A`jOTvOc<0Zkuj z+o^3ckr43u1Pl2YSn!wV=%CDf$QL38t-?+CK!?To&4%+P$b#WZwbN-9Wxb1hz7$rj zLI))l7*g-3BVB5o7xTeb*uS*5_yOc4;#->er$3eNTGFP-_SXq-yFH%6s4BlSRrB!!TQ&*=Na*=FA=7=Zug{pKf}yOAo~yz+V(qc*eRI7X1A&HFgX!<@ zy^1Z}u`7bl+DEL9G?riCX@8^FdX8Rm>ciSvdXOp9cY zI^?;OvdGzZ`T!3AV8G$k|FKQsSX_AIp+rW&b8kosdz87tY#Y46m(Dz7yNS=@lk}dD z`V$#^Z8qYq8+2~gMGhH-bT<}E8X9?3SGsz36#HdVNZk6 z=c-GA@+olL-HaV&hkysVF@skLrFqrhG(zV#C9L9fz^p4K!n&R+n5$F1&jgg~lFwtk zWsB$l@MKrG;MtFRB(6&@U@5sh=v+Dk z^BD{`=(mcukuw)-qf1R+516zTcyrtFb$=XPa%INp(~Q%}$tu=(91$4W>#wi>JYrhQ z)Qxw6`1x^Tn{qHBD!KlK2E~aWv2Y#q3#%+(5<9CR`NAlv#%zv z`kB~ja*}wd?Ux-fTD6zA*Lbq;U&$KC{)j;9`QiPvm(t6Qhb|g?_#p2s6ZE7dZGE<2 z&R5dL?SXUWmP;^L)y|B|SoYIs&80SxR|?DV$JMjrL+>E zkCMtt_uSjFgqYkweOSZPkpZLE}6OQAJFvRAEZFKs8 z$=E;?V=(7&-3q|5$t8ZtJI{9~&MY*Ew+N*ol#q9G33yy`ej)fC4qiowQ*Q8qT&?RD z^9WPf&Q27Q>K1;~oG(}O=cOvoP*6!%bm;EWdwtY;#$0+Jnp5aqAO<9b)qV#E6Ebu@ z263j5WORJzs^L~IZJvaZEez4sCBpQb2;e6NVabnz#YLV)3~BU21{PW-7e$Z(KNy~G zw#&RGYcsU1XZa>6ZW1+eww^FTbwU*TwV^f|LAp;Ntaju{6H0fWZyzXGg6653np0k< zzPp{BbmP51&@et_i6L6Pq-s}r_@LyZZ+}4UmB;r|X`uARbI9RY2!3Tt=&k*@V;eG1 zAI*XL7!*r9C?+=DNJ9!&en}Sj%7DGFZzq3D($@Cg8=K!G^2_E9WemeAb~(u7!cys> z+C!o=($Kci>(SuY0>W#=>08w!SM}#7Qqx7`x~*I&<`Z6qn^aw#C8&=HN*l&UyRUT_ z)fzOhZdcff3MkTc$alTB0(c5c>>Z`I!D0;=^}?h%iLW7Q5COb}5{4Y$o*>|=+)!wS zyyInKe`kp$uRdk0(tx=o+ODQ=OH=kr$5whh)N2~FoDgOOofO(vk%c#Tg2Hc$SU6nBp?1i#sFJC)&a!+bGBihshEZ zf#N_RAXuAs7EsCS$D^=oof;jSZ(^u3?H_cIIRx0#(5V1cPKUTdW6x9okOi(I2`{s5 zLaX{S?ML*Dw82D)9~bW#6fIzivl=GXF%MlYjx$RdY>FFZPnegMlUs)(#yq+5Tq z=S!$-MQqGGk#Y#dr=hH9prLaM;%J~91xZXk>4)j%^@kTiRUzUh#E3MX;LN^2{>}`l zxUy>3^^CbOs3X-|cu~oQbdyegq@^teRT7YD0jHhv3_Cx-hbEhlNa7wHk`(AP?n=Z1)PnOy)To4a_dbuC-cW- zdzuw$J>Ji&2cNEySYH@XUM8N((yAn$Ax3S*1rzh&8R5#a87F(WVZ@w!6LE2vg+Z zcLw{fy+alUMHNU+-AV2*K9xgP_NoF#)_qJSfZbJR^eBfa;>|ACoxS-gUqtrY!mGeNg}2{Sv1#t% zyRPuLlbQSSH#ZZV8Z*{+MM8`!I(>sv7pA`}5*}U& zz^@va)BWAJ8u?fIDSEkz*%AF~=vv*%RmiJm#%cZxU89$|2!eor*SD((G){A^+Fc!) zt9RE*EUw;NwFyphHSTxyyLJX#oV6G9uQ+7Rn*1Zq_mlrS&f3Duz0OzdI%h>!an@e$ zzhkT|M%hj4QQ*sOWbA0^FwKg}YJ>nc>Sy}Z+ z`g7GwiZo({XH?%x>1@qNUbc-iBi^DvCV0XSZuIbERP+MR^zBsK>h9;gIkk9=BE2^d zfA=Vq`y7*waxkex!F7{g9Tz-8--^3jF<~k*Ib@mTr^j@7eGYo8S+o7$42C9*1AQ(3 z%)hX;WWa|V)dR&S(OO8!8 zq*Tq{q_{uG{cJWlg6#Cq50MyEYaRIQaeyQ9Or)~gA_xlp=(s?B3xZBH5amZIs@t2%Ncaf8a%1&m0 z#!^G3|FGK?B9kEEF)uJ^T`&m569$3)$7q0uxH7{()Q?UN%xHJ&B%>a-3y(@Rgmi@6 z>n^#Po|JxlJ6OX{9WAfJzjM4fv6%w2$y|ttm=^k%a0zUToIQTj@0|iKns@8n`w}s(b8px<3~vEF-4pNSux@d8n5rKowCX*4R<5YI zhYugXw_5x)buYrxQn0UzWXoy7DhMPEvK0D%Su_{~N2H&8@0uwR8Jvtj%q|>J0W0fh zpDTs3>?>iaDublhV?W)C=9_2YA6@4E7OhRzXejA%$#Jorwq)fdG_gwbGO#vCC{z+y zBqp8~?lT}9ZWjmyuw1u$GLeCJREJhrSokmDtz#pHS4wyp81HoWrSh=I-z8cYlcWI} zBQj+*ZQ5o|%Rq&8bV_U?zPt8Jf%6!5B>-o)RBGh9`3JN;D35kyRu3kY)+|N+D^zz4 zo}QIzbKa@Hpu!4%Rc{(?MGQS_{ke{7&nfQqP&`VDqOV`s_#rFt@d?N5A?kv{WBx{$ zK8a{U(;YDDknW;i23ue%8YUD~618L*wl|AEErWKWC0Ev*x?xDm>rPqRHzsqk1GUUm(pU*V24@*rjuekQ!^PaVI*#c zVlQdCvrE49SmrCN^}AcqOG8R=9|U?Je))oDVPE!BDlPPGpytc(I2EO zB>F@3R&|bJEP8Ax!P|7LAA9%Wp4M&gEb(7YR(ZxM*9MmRod5Ag$%?CUL)6MUQu~K$ zeOK3P6~~UcK+3ZqwGet{=~kBe%9{n7LG;T)_7;uKSYPyPb-Em_xa7n+?aR5+w2a{Q zsN>snL{G7|LcJy$Hzh7|3dsx?2XlXol)I7x6@qN*uF0Rj2=6;ux~h1$`fJX&zb=_1 z1V(}WTPc8pB<@>_T$8l;hP{%;QeRtz`u%T^2M{ntpbe$~-Dke#1DJ-%fN8=&9SjLb jz@-oG6W^ba1ARXLPzyr=&Ts@m3?v3h{+g>K$UgrcNC6eZ literal 3435 zcmbVPc{r5a8y-tD!;GvklM#)vBxBzqvQ9G?TT)F~Lv~^+lVq1Y`z~ZcgltL4E=&s-@$k-BOFHWh`AIVvxM*MF*HC+ zJ!LaMOZ4^jSDVRD736&YXU2phAQUSYM z7rhs}8GhtonP2cyo7MyUrRTs30MPPE|7`#e+Fy5)o3ov_tv5+d`d6~QJ0i9_>e#xS zKIdjj^z@dKI_+lbiJ9SWPkY+st(SIE z1F!F>$#U_OFYb`wth+LTxlfVr(wp$|JiwX}2g}%lPl*pk)v3hw&>WQd7a`N(H(fTk z^Ccp)P;E@{o(ANKwr=b0AwyNlZKGNlzrcg3VEA&+X9><+?(Wd;FMW>(gO##eE}U7f zSF+vzWbi>SQkI3k-N#H-s<3pZX)Z@^{l)h=hvXx|yRt%6H5xNFH#iC zA?-1#xeJb6*ObnbQn=)l&527)bvi?WBRfm)DVbI4>|F(XJ8G93nCH{PKe+46LGsJzE$jb>H`5?uR2=l zTu7amUp?;pq=Fp4(UDYKKM}^7Hi{zekhVyKFTP`7KWQ<0L%%iTPKy5hHQh(3xo%;2xy}{;!wp(__u1s*9Bgua-r0UxVX^V4}5MM{tw4^j6=k&Pxmb(`wXlH6~(+} z`;yE?XbM^gXjWmutn$$d!a=ucwv$#6Uuo~33j(%%=N=_GyZOkWe(u^>GfPh{Egto@ zE0D1vq=ie_vuAc;m&=e}wWmUk7O-H2@335DGJL1dCI#o+6_E0fj7nT(+Aw{n)>F8b z0#nWy$+$n0?KfY)PF=a03+VQJ82=$Q+0D89u*ix^yo*WqNgHT}{I`VrQGS+nr znzgfS_r>VHatEX96Rmv>SRlC8=a?bvnSdv6qvVg*e(jl>Ej{?OB(2&UR*t|L1N-5V zVUv+e{17EBFBn(LO@s`2=ct74a74@5cx_dD5f$1ehGtr@`n<~%G9b-Uy0o15&Ej}O z=@ly>zt*y~oO~|66wts*T+Mfq{p-SnbW;`cOESfVu7o=YZRl|OV-U{xcapa`o!+0@ z-_f(zrFBZZ#GUkQFgo8{ARqlAc96r2S+XIgkWg0{&L;OU)};HDrLk?2;pArHCsnB5 z_Y@Vg3Kic#biqn|kUQA~rN$Hxm7y%j<#Rj4QfH*#)ntW$z*m7;r%DO+1&?7@md%#l zS9$*4Uqh3siC2R&GQmcheVotV=m;sWQ9M?4Uh-DlSi9zy{(eFhufQ;y^ehT4n~|6Y z+hpS*=_;p<$BaMvAX|R9Kqm$ZW&skezsz9tLX(RseYM6>H6&iq2*u8>ONXCfZ^I)| zS{^q0kjb3v1z(u!9hHniod3rxgzBoWUA*E)U~hpkkv`S6@~a;S4w z>-^SWFPGelcTON5c*&9#V8;<71!qjwDG4hAE`aDICub1ahNkgPH`9NW9N)i{+|P-xf*PZE2x?S#(*F&JRbt@bM2&FuCDqW^dDEy^3N z^FYVEV$U1w=9N}wz3q&U!c49gOkAu(4c7-sYG8o8GaJd~7-0Ft#=!MA=5@UY zp(~2*vMMMpEGXnumrYl5dvhy*F-B8evrLl!=;CIGl4o>|!$TVgW3W}_z#$oVFe6SB zXaU?Sgl?YrUjEAX)EfnzfYUX44G)1p+j!)Ullb$C*0OopjA;JnHvRWG`$5_0_(O)= zXL&m3b0Q<aS5Y1{1Bsy zTrpe}*5;U`d08Ud=s{8t@?4xnr# zgIe;_`=hapZEQg!!V_A#rF*1#TVfX_sn*jWm#&b!(vKUaJ^@hqQ*(p%w5(v=Uz1D% z2!v2nRObkDOm1H5L9y4Shm7y+rleU(2IC+HrJpj?vOZ($t=gEzm`DeYiB70sxc0b# zUK;Q42u%wUZ|u7bJJo)+A=GG7x!Lhjar53(ij`;L=(Br*(|DFD%gC%EYfp`})WNps z-bzDewcbv<^d#LK=Xr)%Z@L&wopV+qkKQ>$AZFp~*;IL!k?-zMN2Y4BS?kRm>=_|A ziLw)zq-+)k{@VACL=PMunmgNn?Z&jWxUv6S(X&2aP5)K=42yMg^d#cwR5T^%0rjZF z`9}s1VvbFXJgM4X`nD*KAtIizfXMaT!o)?Q$A0EyX zTt8XCy_qOWqhE2LHWtyzk_UD@a-T5v@6FyQjz*= UJUf8&-oUhHH*M@{^s5Nqf37t~djJ3c diff --git a/compiler/test-resources/repl/require-multiple b/compiler/test-resources/repl/require-multiple index 34faa564d37d..3803234141d6 100644 --- a/compiler/test-resources/repl/require-multiple +++ b/compiler/test-resources/repl/require-multiple @@ -15,7 +15,7 @@ Added 'compiler/test-resources/jars/mylibrary2.jar' to classpath. scala> import mylibrary2.Utils2 scala> Utils2.greet("Alice") -val res1: String = Hello, Alice! +val res1: String = Greetings, Alice! scala> Utils.greet("Alice") val res2: String = Hello, Alice! From 7febea66b19cc730625ab440305ee12905188426 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Thu, 13 Feb 2025 23:53:46 +0000 Subject: [PATCH 177/505] Fix :require adding classes/pkgs --- .../dotc/classpath/AggregateClassPath.scala | 6 +--- .../tools/dotc/config/JavaPlatform.scala | 3 +- .../dotty/tools/dotc/config/Platform.scala | 2 +- .../src/dotty/tools/dotc/core/Contexts.scala | 6 +--- .../dotty/tools/dotc/core/Definitions.scala | 2 +- .../dotty/tools/dotc/core/SymbolLoaders.scala | 29 ++++++++++++++- .../src/dotty/tools/repl/ReplCompiler.scala | 6 +--- .../src/dotty/tools/repl/ReplDriver.scala | 35 +++++++++---------- compiler/test/dotty/tools/repl/ReplTest.scala | 5 +-- 9 files changed, 52 insertions(+), 42 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/classpath/AggregateClassPath.scala b/compiler/src/dotty/tools/dotc/classpath/AggregateClassPath.scala index 699e2f438e4e..ec04eb3db8a1 100644 --- a/compiler/src/dotty/tools/dotc/classpath/AggregateClassPath.scala +++ b/compiler/src/dotty/tools/dotc/classpath/AggregateClassPath.scala @@ -51,11 +51,7 @@ case class AggregateClassPath(aggregates: Seq[ClassPath]) extends ClassPath { case (_, s) => s } } - override def asURLs: Seq[URL] = - aggregates.flatMap { - case v: VirtualDirectoryClassPath => Seq() - case a => a.asURLs - } + override def asURLs: Seq[URL] = aggregates.flatMap(_.asURLs) override def asClassPathStrings: Seq[String] = aggregates.map(_.asClassPathString).distinct diff --git a/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala b/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala index 80deb207be0c..7f6b5025cea6 100644 --- a/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala +++ b/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala @@ -33,8 +33,9 @@ class JavaPlatform extends Platform { case cp: ClassPath => currentClassPath = Some(AggregateClassPath(cp :: cPath :: Nil)) } + /** Update classpath with a substituted subentry */ - def updateClassPath(subst: Map[ClassPath, ClassPath])(using Context): Unit = classPath match { + def updateClassPath(subst: Map[ClassPath, ClassPath]): Unit = currentClassPath.get match { case AggregateClassPath(entries) => currentClassPath = Some(AggregateClassPath(entries map (e => subst.getOrElse(e, e)))) case cp: ClassPath => diff --git a/compiler/src/dotty/tools/dotc/config/Platform.scala b/compiler/src/dotty/tools/dotc/config/Platform.scala index 6c3542bc2e6c..798c9f449f9a 100644 --- a/compiler/src/dotty/tools/dotc/config/Platform.scala +++ b/compiler/src/dotty/tools/dotc/config/Platform.scala @@ -19,7 +19,7 @@ abstract class Platform { def classPath(using Context): ClassPath /** Update classpath with a substitution that maps entries to entries */ - def updateClassPath(subst: Map[ClassPath, ClassPath])(using Context): Unit + def updateClassPath(subst: Map[ClassPath, ClassPath]): Unit /** Add new entry to classpath */ def addToClassPath(cPath: ClassPath)(using Context): Unit diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index 075de9e934fe..8c09a3f24fa0 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -35,7 +35,6 @@ import scala.annotation.internal.sharable import DenotTransformers.DenotTransformer import dotty.tools.dotc.profile.Profiler import dotty.tools.dotc.sbt.interfaces.{IncrementalCallback, ProgressCallback} -import dotty.tools.dotc.classpath.ClassPathFactory import util.Property.Key import util.Store import plugins.* @@ -898,11 +897,8 @@ object Contexts { /** Initializes the `ContextBase` with a starting context. * This initializes the `platform` and the `definitions`. */ - def initialize(previousOutputDir: Option[AbstractFile] = None)(using Context): Unit = { + def initialize()(using Context): Unit = { _platform = newPlatform - previousOutputDir.foreach(cp => - _platform.nn.addToClassPath(ClassPathFactory.newClassPath(cp)) - ) definitions.init() } diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 5c7d3786bd7e..da57315e15ff 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -2150,7 +2150,7 @@ class Definitions { private var isInitialized = false - def init(require: Boolean = false)(using Context): Unit = { + def init()(using Context): Unit = { this.initCtx = ctx if (!isInitialized) { // force initialization of every symbol that is synthesized or hijacked by the compiler diff --git a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala index a0b3460d06e4..bcb61ca47b3e 100644 --- a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -7,6 +7,7 @@ import java.nio.channels.ClosedByInterruptException import scala.util.control.NonFatal +import dotty.tools.dotc.classpath.PackageNameUtils import dotty.tools.io.{ ClassPath, ClassRepresentation, AbstractFile, NoAbstractFile } import dotty.tools.backend.jvm.DottyBackendInterface.symExtensions @@ -265,7 +266,7 @@ object SymbolLoaders { def maybeModuleClass(classRep: ClassRepresentation): Boolean = classRep.name.last == '$' - private def enterClasses(root: SymDenotation, packageName: String, flat: Boolean)(using Context) = { + def enterClasses(root: SymDenotation, packageName: String, flat: Boolean)(using Context) = { def isAbsent(classRep: ClassRepresentation) = !root.unforcedDecls.lookup(classRep.name.toTypeName).exists @@ -309,6 +310,32 @@ object SymbolLoaders { } } } + + def mergeNewEntries( + packageClass: ClassSymbol, fullPackageName: String, + jarClasspath: ClassPath, fullClasspath: ClassPath, + )(using Context): Unit = + if jarClasspath.classes(fullPackageName).nonEmpty then + // if the package contains classes in jarClasspath, the package is invalidated (or removed if there are no more classes in it) + val packageVal = packageClass.sourceModule.asInstanceOf[TermSymbol] + if packageClass.isRoot then + val loader = new PackageLoader(packageVal, fullClasspath) + loader.enterClasses(defn.EmptyPackageClass, fullPackageName, flat = false) + loader.enterClasses(defn.EmptyPackageClass, fullPackageName, flat = true) + else if packageClass.ownersIterator.contains(defn.ScalaPackageClass) then + () // skip + else if fullClasspath.hasPackage(fullPackageName) then + packageClass.info = new PackageLoader(packageVal, fullClasspath) + else + packageClass.owner.info.decls.openForMutations.unlink(packageVal) + else + for p <- jarClasspath.packages(fullPackageName) do + val subPackageName = PackageNameUtils.separatePkgAndClassNames(p.name)._2.toTermName + val subPackage = packageClass.info.decl(subPackageName).orElse: + // package does not exist in symbol table, create a new symbol + enterPackage(packageClass, subPackageName, (module, modcls) => new PackageLoader(module, fullClasspath)) + mergeNewEntries(subPackage.asSymDenotation.moduleClass.asClass, p.name, jarClasspath, fullClasspath) + end mergeNewEntries } /** A lazy type that completes itself by calling parameter doComplete. diff --git a/compiler/src/dotty/tools/repl/ReplCompiler.scala b/compiler/src/dotty/tools/repl/ReplCompiler.scala index 1ec2d230f7e9..e34bb229a727 100644 --- a/compiler/src/dotty/tools/repl/ReplCompiler.scala +++ b/compiler/src/dotty/tools/repl/ReplCompiler.scala @@ -46,11 +46,7 @@ class ReplCompiler extends Compiler: /** Import previous runs and user defined imports */ override protected def rootContext(using Context): Context = { def importContext(imp: tpd.Import)(using Context) = - // TODO: only when context has changed? - val typer = ctx.typer - typer.index(imp) - val imp2 = typer.typed(imp).asInstanceOf[tpd.Import] - ctx.importContext(imp2, imp2.symbol) + ctx.importContext(imp, imp.symbol) def importPreviousRun(id: Int)(using Context) = { // we first import the wrapper object id diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 136b019a33ea..180612830c6e 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -1,8 +1,10 @@ package dotty.tools.repl import scala.language.unsafeNulls + import java.io.{File => JFile, PrintStream} import java.nio.charset.StandardCharsets + import dotty.tools.dotc.ast.Trees.* import dotty.tools.dotc.ast.{tpd, untpd} import dotty.tools.dotc.classpath.ClassPathFactory @@ -20,6 +22,7 @@ import dotty.tools.dotc.core.NameOps.* import dotty.tools.dotc.core.Names.Name import dotty.tools.dotc.core.StdNames.* import dotty.tools.dotc.core.Symbols.{Symbol, defn} +import dotty.tools.dotc.core.SymbolLoaders import dotty.tools.dotc.interfaces import dotty.tools.dotc.interactive.Completion import dotty.tools.dotc.printing.SyntaxHighlighting @@ -69,6 +72,7 @@ case class State(objectIndex: Int, quiet: Boolean, context: Context): def validObjectIndexes = (1 to objectIndex).filterNot(invalidObjectIndexes.contains(_)) + //def copy() = this /** Main REPL instance, orchestrating input, compilation and presentation */ class ReplDriver(settings: Array[String], @@ -88,12 +92,12 @@ class ReplDriver(settings: Array[String], setupRootCtx(this.settings ++ settings, rootCtx) } - private def setupRootCtx(settings: Array[String], rootCtx: Context, previousOutputDir: Option[AbstractFile] = None) = { + private def setupRootCtx(settings: Array[String], rootCtx: Context) = { setup(settings, rootCtx) match case Some((files, ictx)) => inContext(ictx) { shouldStart = true if files.nonEmpty then out.println(i"Ignoring spurious arguments: $files%, %") - ictx.base.initialize(previousOutputDir) + ictx.base.initialize() ictx } case None => @@ -543,30 +547,23 @@ class ReplDriver(settings: Array[String], if (existingClass.nonEmpty) out.println(s"The path '$path' cannot be loaded, it contains a classfile that already exists on the classpath: ${existingClass.get}") state - else - val prevClassPath = state.context.platform.classPath(using state.context).asClassPathString - val newClassPath = s"$prevClassPath${JFile.pathSeparator}$path" + else inContext(state.context): + val jarClassPath = ClassPathFactory.newClassPath(jarFile) + val prevOutputDir = ctx.settings.outputDir.value // add to compiler class path - val prevOutputDir = rootCtx.settings.outputDir.valueIn(rootCtx.settingsState) - val ctxToUse = initCtx.fresh - .setSetting(rootCtx.settings.classpath, newClassPath) - .setSetting(rootCtx.settings.outputDir, prevOutputDir) // reuse virtual output directory - rootCtx = setupRootCtx( - Array(), - ctxToUse, - previousOutputDir = Some(prevOutputDir) - ) - val s = state.copy(context = rootCtx) + ctx.platform.addToClassPath(jarClassPath) + SymbolLoaders.mergeNewEntries(defn.RootClass, ClassPath.RootPackage, jarClassPath, ctx.platform.classPath) // new class loader with previous output dir and specified jar - val prevClassLoader = rendering.classLoader()(using state.context) + val prevClassLoader = rendering.classLoader() val jarClassLoader = fromURLsParallelCapable( - ClassPathFactory.newClassPath(jarFile)(using rootCtx).asURLs, prevClassLoader) + jarClassPath.asURLs, prevClassLoader) rendering.myClassLoader = new AbstractFileClassLoader( - rootCtx.settings.outputDir.valueIn(rootCtx.settingsState), jarClassLoader) + prevOutputDir, jarClassLoader) + out.println(s"Added '$path' to classpath.") - s + state case KindOf(expr) => out.println(s"""The :kind command is not currently supported.""") diff --git a/compiler/test/dotty/tools/repl/ReplTest.scala b/compiler/test/dotty/tools/repl/ReplTest.scala index 8fbf635c9a17..b630ef0c2b82 100644 --- a/compiler/test/dotty/tools/repl/ReplTest.scala +++ b/compiler/test/dotty/tools/repl/ReplTest.scala @@ -94,10 +94,7 @@ extends ReplDriver(options, new PrintStream(out, true, StandardCharsets.UTF_8.na FileDiff.dump(checkFile.toPath.toString, actualOutput) println(s"Wrote updated script file to $checkFile") else - println("expected =========>") - println(expectedOutput.mkString(EOL)) - println("actual ===========>") - println(actualOutput.mkString(EOL)) + println(dotc.util.DiffUtil.mkColoredHorizontalLineDiff(actualOutput.mkString(EOL), expectedOutput.mkString(EOL))) fail(s"Error in script $name, expected output did not match actual") end if From a40d3880bca16cc69899861d40e247297125e89a Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Fri, 25 Apr 2025 08:36:37 +0200 Subject: [PATCH 178/505] Fix :require adding classes/pkgs [Cherry-picked 9a6067993748c659b7c76c5361993335ef5a13a9][modified] From e9be78e8269afe6a03854cbef7284d9a62bf57d5 Mon Sep 17 00:00:00 2001 From: aherlihy Date: Wed, 26 Feb 2025 10:36:30 +0100 Subject: [PATCH 179/505] Rename :require to :jar and deprecate :require [Cherry-picked 4649d5e7abe5fe968621f700369df90dd22ea6b4] --- .../src/dotty/tools/repl/ParseResult.scala | 10 +++++- .../src/dotty/tools/repl/ReplDriver.scala | 4 +++ compiler/test-resources/jars/MyLibrary.scala | 2 +- compiler/test-resources/jars/MyLibrary2.scala | 2 +- compiler/test-resources/repl/require-command | 13 -------- compiler/test-resources/repl/require-errors | 8 ----- compiler/test-resources/repl/require-multiple | 32 ------------------- .../dotty/tools/repl/TabcompleteTests.scala | 1 + 8 files changed, 16 insertions(+), 56 deletions(-) delete mode 100644 compiler/test-resources/repl/require-command delete mode 100644 compiler/test-resources/repl/require-errors delete mode 100644 compiler/test-resources/repl/require-multiple diff --git a/compiler/src/dotty/tools/repl/ParseResult.scala b/compiler/src/dotty/tools/repl/ParseResult.scala index 409572aeacf6..2b7740152fa4 100644 --- a/compiler/src/dotty/tools/repl/ParseResult.scala +++ b/compiler/src/dotty/tools/repl/ParseResult.scala @@ -52,13 +52,20 @@ object Load { val command: String = ":load" } -/** `:require ` adds a jar to the classpath +/** `:require` is a deprecated alias for :jar` */ case class Require(path: String) extends Command object Require { val command: String = ":require" } +/** `:jar ` adds a jar to the classpath + */ +case class JarCmd(path: String) extends Command +object JarCmd { + val command: String = ":jar" +} + /** `:kind ` display the kind of a type. see also :help kind */ case class KindOf(expr: String) extends Command @@ -158,6 +165,7 @@ object ParseResult { Help.command -> (_ => Help), Reset.command -> (arg => Reset(arg)), Imports.command -> (_ => Imports), + JarCmd.command -> (arg => JarCmd(arg)), KindOf.command -> (arg => KindOf(arg)), Load.command -> (arg => Load(arg)), Require.command -> (arg => Require(arg)), diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 180612830c6e..599db1994d7d 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -518,6 +518,10 @@ class ReplDriver(settings: Array[String], } case Require(path) => + out.println(":require has been deprecated and replaced with :jar. Please use :jar") + state + + case JarCmd(path) => val jarFile = AbstractFile.getDirectory(path) if (jarFile == null) out.println(s"""Cannot add "$path" to classpath.""") diff --git a/compiler/test-resources/jars/MyLibrary.scala b/compiler/test-resources/jars/MyLibrary.scala index cc492696c139..bd752d2df864 100644 --- a/compiler/test-resources/jars/MyLibrary.scala +++ b/compiler/test-resources/jars/MyLibrary.scala @@ -1,5 +1,5 @@ /** - * JAR used for testing repl :require + * JAR used for testing repl :jar * Generated using: mkdir out; scalac -d out MyLibrary.scala; jar cf mylibrary.jar -C out . */ package mylibrary diff --git a/compiler/test-resources/jars/MyLibrary2.scala b/compiler/test-resources/jars/MyLibrary2.scala index ca288fcfbf85..df5a944c0bcf 100644 --- a/compiler/test-resources/jars/MyLibrary2.scala +++ b/compiler/test-resources/jars/MyLibrary2.scala @@ -1,5 +1,5 @@ /** - * JAR used for testing repl :require + * JAR used for testing repl :jar * Generated using: mkdir out2; scalac -d out MyLibrary2.scala; jar cf mylibrary2.jar -C out2 . */ package mylibrary2 diff --git a/compiler/test-resources/repl/require-command b/compiler/test-resources/repl/require-command deleted file mode 100644 index 1af49ccff6fb..000000000000 --- a/compiler/test-resources/repl/require-command +++ /dev/null @@ -1,13 +0,0 @@ -scala> val z = 1 -val z: Int = 1 - -scala>:require sbt-test/source-dependencies/canon/actual/a.jar -Added 'sbt-test/source-dependencies/canon/actual/a.jar' to classpath. - -scala> import A.x - -scala> x -val res0: Int = 3 - -scala> z -val res1: Int = 1 diff --git a/compiler/test-resources/repl/require-errors b/compiler/test-resources/repl/require-errors deleted file mode 100644 index 8e26c673f9b3..000000000000 --- a/compiler/test-resources/repl/require-errors +++ /dev/null @@ -1,8 +0,0 @@ -scala>:require path/does/not/exist -Cannot add "path/does/not/exist" to classpath. - -scala>:require sbt-test/source-dependencies/canon/actual/a.jar -Added 'sbt-test/source-dependencies/canon/actual/a.jar' to classpath. - -scala>:require sbt-test/source-dependencies/canon/actual/a.jar -The path 'sbt-test/source-dependencies/canon/actual/a.jar' cannot be loaded, it contains a classfile that already exists on the classpath: sbt-test/source-dependencies/canon/actual/a.jar(A.class) diff --git a/compiler/test-resources/repl/require-multiple b/compiler/test-resources/repl/require-multiple deleted file mode 100644 index 3803234141d6..000000000000 --- a/compiler/test-resources/repl/require-multiple +++ /dev/null @@ -1,32 +0,0 @@ -scala> val z = 1 -val z: Int = 1 - -scala>:require compiler/test-resources/jars/mylibrary.jar -Added 'compiler/test-resources/jars/mylibrary.jar' to classpath. - -scala> import mylibrary.Utils - -scala> Utils.greet("Alice") -val res0: String = Hello, Alice! - -scala>:require compiler/test-resources/jars/mylibrary2.jar -Added 'compiler/test-resources/jars/mylibrary2.jar' to classpath. - -scala> import mylibrary2.Utils2 - -scala> Utils2.greet("Alice") -val res1: String = Greetings, Alice! - -scala> Utils.greet("Alice") -val res2: String = Hello, Alice! - -scala> import mylibrary.Utils.greet - -scala> greet("Tom") -val res3: String = Hello, Tom! - -scala> Utils.greet("Alice") -val res4: String = Hello, Alice! - -scala> z -val res5: Int = 1 diff --git a/compiler/test/dotty/tools/repl/TabcompleteTests.scala b/compiler/test/dotty/tools/repl/TabcompleteTests.scala index 75ecb03b95d7..d8518e9f41dc 100644 --- a/compiler/test/dotty/tools/repl/TabcompleteTests.scala +++ b/compiler/test/dotty/tools/repl/TabcompleteTests.scala @@ -216,6 +216,7 @@ class TabcompleteTests extends ReplTest { ":exit", ":help", ":imports", + ":jar", ":kind", ":load", ":quit", From 49a57104b192aad75c0f7c4136a975213d089a4a Mon Sep 17 00:00:00 2001 From: anna herlihy Date: Tue, 4 Mar 2025 12:54:24 +0100 Subject: [PATCH 180/505] Update compiler/src/dotty/tools/repl/ReplDriver.scala MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Oliver Bračevac [Cherry-picked 46aef8759adfd970d062e4980ab0bb6e82f0d6fc] --- compiler/src/dotty/tools/repl/ReplDriver.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 599db1994d7d..6311f310e88a 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -72,7 +72,6 @@ case class State(objectIndex: Int, quiet: Boolean, context: Context): def validObjectIndexes = (1 to objectIndex).filterNot(invalidObjectIndexes.contains(_)) - //def copy() = this /** Main REPL instance, orchestrating input, compilation and presentation */ class ReplDriver(settings: Array[String], From b1264fb30064ee5fa1f6a66ae129b7a259c322f1 Mon Sep 17 00:00:00 2001 From: aherlihy Date: Tue, 4 Mar 2025 13:00:15 +0100 Subject: [PATCH 181/505] re-add tests [Cherry-picked 7b142b821126771a6a986f9ad998f870f8f5d356] --- compiler/test-resources/repl/jar-command | 13 +++++++++ compiler/test-resources/repl/jar-errors | 11 ++++++++ compiler/test-resources/repl/jar-multiple | 32 +++++++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 compiler/test-resources/repl/jar-command create mode 100644 compiler/test-resources/repl/jar-errors create mode 100644 compiler/test-resources/repl/jar-multiple diff --git a/compiler/test-resources/repl/jar-command b/compiler/test-resources/repl/jar-command new file mode 100644 index 000000000000..b0ded22d3654 --- /dev/null +++ b/compiler/test-resources/repl/jar-command @@ -0,0 +1,13 @@ +scala> val z = 1 +val z: Int = 1 + +scala>:jar sbt-test/source-dependencies/canon/actual/a.jar +Added 'sbt-test/source-dependencies/canon/actual/a.jar' to classpath. + +scala> import A.x + +scala> x +val res0: Int = 3 + +scala> z +val res1: Int = 1 diff --git a/compiler/test-resources/repl/jar-errors b/compiler/test-resources/repl/jar-errors new file mode 100644 index 000000000000..53a3ba965c94 --- /dev/null +++ b/compiler/test-resources/repl/jar-errors @@ -0,0 +1,11 @@ +scala>:jar path/does/not/exist +Cannot add "path/does/not/exist" to classpath. + +scala>:jar sbt-test/source-dependencies/canon/actual/a.jar +Added 'sbt-test/source-dependencies/canon/actual/a.jar' to classpath. + +scala>:jar sbt-test/source-dependencies/canon/actual/a.jar +The path 'sbt-test/source-dependencies/canon/actual/a.jar' cannot be loaded, it contains a classfile that already exists on the classpath: sbt-test/source-dependencies/canon/actual/a.jar(A.class) + +scala>:require sbt-test/source-dependencies/canon/actual/a.jar +:require has been deprecated and replaced with :jar. Please use :jar \ No newline at end of file diff --git a/compiler/test-resources/repl/jar-multiple b/compiler/test-resources/repl/jar-multiple new file mode 100644 index 000000000000..453ccc40dbf6 --- /dev/null +++ b/compiler/test-resources/repl/jar-multiple @@ -0,0 +1,32 @@ +scala> val z = 1 +val z: Int = 1 + +scala>:jar compiler/test-resources/jars/mylibrary.jar +Added 'compiler/test-resources/jars/mylibrary.jar' to classpath. + +scala> import mylibrary.Utils + +scala> Utils.greet("Alice") +val res0: String = Hello, Alice! + +scala>:jar compiler/test-resources/jars/mylibrary2.jar +Added 'compiler/test-resources/jars/mylibrary2.jar' to classpath. + +scala> import mylibrary2.Utils2 + +scala> Utils2.greet("Alice") +val res1: String = Greetings, Alice! + +scala> Utils.greet("Alice") +val res2: String = Hello, Alice! + +scala> import mylibrary.Utils.greet + +scala> greet("Tom") +val res3: String = Hello, Tom! + +scala> Utils.greet("Alice") +val res4: String = Hello, Alice! + +scala> z +val res5: Int = 1 From f14495b2c7d56a530817df4d01b34d63d77e4779 Mon Sep 17 00:00:00 2001 From: anna herlihy Date: Mon, 10 Mar 2025 13:23:25 +0100 Subject: [PATCH 182/505] Update compiler/src/dotty/tools/repl/ReplDriver.scala Co-authored-by: Piotr Chabelski [Cherry-picked 4bb08f7c7fe315a7281879a01d6a8d200b40df29] --- compiler/src/dotty/tools/repl/ReplDriver.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 6311f310e88a..825c78e8ee7a 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -517,7 +517,7 @@ class ReplDriver(settings: Array[String], } case Require(path) => - out.println(":require has been deprecated and replaced with :jar. Please use :jar") + out.println(":require is no longer supported, but has been replaced with :jar. Please use :jar") state case JarCmd(path) => From bf8d90322fe1515d5d15e3cb823a904fda3cb367 Mon Sep 17 00:00:00 2001 From: aherlihy Date: Mon, 10 Mar 2025 13:33:23 +0100 Subject: [PATCH 183/505] Add wrapper around :jar to avoid crashing repl on invalid jar [Cherry-picked 42c4e89c738042f32690de7a2a70fad68bfeb213] --- .../src/dotty/tools/repl/ReplDriver.scala | 50 ++++++++++--------- compiler/test-resources/repl/jar-errors | 2 +- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 825c78e8ee7a..f32b1fd5281c 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -530,8 +530,6 @@ class ReplDriver(settings: Array[String], if (f.isClassContainer) f.iterator.flatMap(flatten) else Iterator(f) - val entries = flatten(jarFile) - def tryClassLoad(classFile: AbstractFile): Option[String] = { val input = classFile.input try { @@ -546,27 +544,33 @@ class ReplDriver(settings: Array[String], } } - val existingClass = entries.filter(_.ext.isClass).find(tryClassLoad(_).isDefined) - if (existingClass.nonEmpty) - out.println(s"The path '$path' cannot be loaded, it contains a classfile that already exists on the classpath: ${existingClass.get}") - state - else inContext(state.context): - val jarClassPath = ClassPathFactory.newClassPath(jarFile) - val prevOutputDir = ctx.settings.outputDir.value - - // add to compiler class path - ctx.platform.addToClassPath(jarClassPath) - SymbolLoaders.mergeNewEntries(defn.RootClass, ClassPath.RootPackage, jarClassPath, ctx.platform.classPath) - - // new class loader with previous output dir and specified jar - val prevClassLoader = rendering.classLoader() - val jarClassLoader = fromURLsParallelCapable( - jarClassPath.asURLs, prevClassLoader) - rendering.myClassLoader = new AbstractFileClassLoader( - prevOutputDir, jarClassLoader) - - out.println(s"Added '$path' to classpath.") - state + try { + val entries = flatten(jarFile) + + val existingClass = entries.filter(_.ext.isClass).find(tryClassLoad(_).isDefined) + if (existingClass.nonEmpty) + out.println(s"The path '$path' cannot be loaded, it contains a classfile that already exists on the classpath: ${existingClass.get}") + else inContext(state.context): + val jarClassPath = ClassPathFactory.newClassPath(jarFile) + val prevOutputDir = ctx.settings.outputDir.value + + // add to compiler class path + ctx.platform.addToClassPath(jarClassPath) + SymbolLoaders.mergeNewEntries(defn.RootClass, ClassPath.RootPackage, jarClassPath, ctx.platform.classPath) + + // new class loader with previous output dir and specified jar + val prevClassLoader = rendering.classLoader() + val jarClassLoader = fromURLsParallelCapable( + jarClassPath.asURLs, prevClassLoader) + rendering.myClassLoader = new AbstractFileClassLoader( + prevOutputDir, jarClassLoader) + + out.println(s"Added '$path' to classpath.") + } catch { + case e: Throwable => + out.println(s"Failed to load '$path' to classpath: ${e.getMessage}") + } + state case KindOf(expr) => out.println(s"""The :kind command is not currently supported.""") diff --git a/compiler/test-resources/repl/jar-errors b/compiler/test-resources/repl/jar-errors index 53a3ba965c94..7d5720fcb233 100644 --- a/compiler/test-resources/repl/jar-errors +++ b/compiler/test-resources/repl/jar-errors @@ -8,4 +8,4 @@ scala>:jar sbt-test/source-dependencies/canon/actual/a.jar The path 'sbt-test/source-dependencies/canon/actual/a.jar' cannot be loaded, it contains a classfile that already exists on the classpath: sbt-test/source-dependencies/canon/actual/a.jar(A.class) scala>:require sbt-test/source-dependencies/canon/actual/a.jar -:require has been deprecated and replaced with :jar. Please use :jar \ No newline at end of file +:require is no longer supported, but has been replaced with :jar. Please use :jar \ No newline at end of file From 7317ab60985764184c77dd80a04ec7c891b81ab2 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Fri, 7 Mar 2025 13:06:55 -0800 Subject: [PATCH 184/505] Ignore params to default arg getters --- .../tools/dotc/transform/CheckUnused.scala | 6 ++++-- tests/warn/i22746.scala | 21 +++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 tests/warn/i22746.scala diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index 61c18180420f..17d5a07bf18e 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -8,7 +8,8 @@ import dotty.tools.dotc.core.Contexts.* import dotty.tools.dotc.core.Flags.* import dotty.tools.dotc.core.Names.{Name, SimpleName, DerivedName, TermName, termName} import dotty.tools.dotc.core.NameOps.{isAnonymousFunctionName, isReplWrapperName, isContextFunction} -import dotty.tools.dotc.core.NameKinds.{BodyRetainerName, ContextBoundParamName, ContextFunctionParamName, WildcardParamName} +import dotty.tools.dotc.core.NameKinds.{ + BodyRetainerName, ContextBoundParamName, ContextFunctionParamName, DefaultGetterName, WildcardParamName} import dotty.tools.dotc.core.StdNames.nme import dotty.tools.dotc.core.Symbols.{ClassSymbol, NoSymbol, Symbol, defn, isDeprecated, requiredClass, requiredModule} import dotty.tools.dotc.core.Types.* @@ -173,7 +174,8 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha override def prepareForDefDef(tree: DefDef)(using Context): Context = def trivial = tree.symbol.is(Deferred) || isUnconsuming(tree.rhs) def nontrivial = tree.symbol.isConstructor || tree.symbol.isAnonymousFunction - if !nontrivial && trivial then + def isDefault = tree.symbol.name.is(DefaultGetterName) + if !nontrivial && trivial || isDefault then refInfos.skip.addOne(tree.symbol) if tree.symbol.is(Inline) then refInfos.inliners += 1 diff --git a/tests/warn/i22746.scala b/tests/warn/i22746.scala new file mode 100644 index 000000000000..79576f5924be --- /dev/null +++ b/tests/warn/i22746.scala @@ -0,0 +1,21 @@ + +//> using options -Wunused:all -Werror + +import java.time.ZonedDateTime + +trait Foo[A] { + def apply(a: A, t: ZonedDateTime): A +} + +extension [A](a: A)(using f: Foo[A]) { + def foo(t: ZonedDateTime = ZonedDateTime.now): A = f(a, t) +} + +def test[I, A](in: I)( + run: I => Either[Throwable, A], + onErr: Throwable => Throwable = identity[Throwable] +): Either[Throwable, A] = + run(in) match { + case Left(t) => Left(onErr(t)) + case r @ Right(_) => r + } From 8900b86d0c6f4fd5d061953628f8b7838c432e5a Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Fri, 25 Apr 2025 08:37:27 +0200 Subject: [PATCH 185/505] Ignore params to default arg getters [Cherry-picked 77c3efb2db41802338d05da15cbb65a015e07be5][modified] From 9ea521a0a051fc564c3f5bc549460346cf7ca006 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Sat, 8 Mar 2025 00:08:35 -0800 Subject: [PATCH 186/505] Lazy val def member is pattern var --- compiler/src/dotty/tools/dotc/ast/Desugar.scala | 4 +++- compiler/src/dotty/tools/dotc/transform/CheckUnused.scala | 8 ++++---- tests/warn/i15503d.scala | 6 ++++++ 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 0666cea91f20..0f4421698240 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -14,11 +14,11 @@ import config.Feature.{sourceVersion, migrateTo3, enabled} import config.SourceVersion.* import collection.mutable.ListBuffer import reporting.* -import annotation.constructorOnly import printing.Formatting.hl import config.Printers import scala.annotation.internal.sharable +import scala.annotation.{unchecked as _, *} import dotty.tools.dotc.util.SrcPos object desugar { @@ -1255,6 +1255,7 @@ object desugar { DefDef(named.name.asTermName, Nil, tpt, selector(n)) .withMods(mods &~ Lazy) .withSpan(named.span) + .withAttachment(PatternVar, ()) else valDef( ValDef(named.name.asTermName, tpt, selector(n)) @@ -1557,6 +1558,7 @@ object desugar { mayNeedSetter } + @unused private def derivedDefDef(original: Tree, named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers)(implicit src: SourceFile) = DefDef(named.name.asTermName, Nil, tpt, rhs) .withMods(mods) diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index 17d5a07bf18e..4b0e11c33759 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -455,11 +455,11 @@ object CheckUnused: case tree: Bind => if !tree.name.isInstanceOf[DerivedName] && !tree.name.is(WildcardParamName) && !tree.hasAttachment(NoWarn) then pats.addOne((tree.symbol, tree.namePos)) - case tree: ValDef if tree.hasAttachment(PatternVar) => - if !tree.name.isInstanceOf[DerivedName] then - pats.addOne((tree.symbol, tree.namePos)) case tree: NamedDefTree => - if (tree.symbol ne NoSymbol) + if tree.hasAttachment(PatternVar) then + if !tree.name.isInstanceOf[DerivedName] then + pats.addOne((tree.symbol, tree.namePos)) + else if (tree.symbol ne NoSymbol) && !tree.name.isWildcard && !tree.hasAttachment(NoWarn) && !tree.symbol.is(ModuleVal) // track only the ModuleClass using the object symbol, with correct namePos diff --git a/tests/warn/i15503d.scala b/tests/warn/i15503d.scala index 2981986daff6..1e1adca51b46 100644 --- a/tests/warn/i15503d.scala +++ b/tests/warn/i15503d.scala @@ -115,3 +115,9 @@ object `mutable patvar in for`: class `unset var requires -Wunused`: private var i = 0 // no warn as we didn't ask for it def f = println(i) + +class `i22743 lazy vals are defs`: + def f: (Int, String) = (42, "hello, world") + lazy val (i, s) = f // no warn because def is neither local nor private + val (j, t) = f // existing no warn for val with attachment + private lazy val (k, u) = f // warn // warn a warning so nice, they warn it twice From 09fb930b5cda94ceaee065fd819a9f6f8943c914 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Fri, 25 Apr 2025 08:38:00 +0200 Subject: [PATCH 187/505] Lazy val def member is pattern var [Cherry-picked 40ca110c8ceb9610477a2647645d309fd91534c4][modified] From b713012241f8c0b07cb2841fc8e35d68e10146a8 Mon Sep 17 00:00:00 2001 From: som-snytt Date: Mon, 10 Mar 2025 16:24:24 -0700 Subject: [PATCH 188/505] Dealias before checking for member in lint (#22708) Fixes #22705 Fixes #22706 Fixes #22727 Follow-up to https://github.com/scala/scala3/pull/22502 by inserting a `dealias` when arriving at `target` type. Refactored the body of `hidden` to make it easier to read. Adjusted the doc for the same reason. As a reminder to self, the original reason for special handling of aliases was due to subclassing, but overrides are excluded. (One could restore that warning for edge cases.) The long doc explaining the handling of leading implicits is moved to the end (as an appendix). Despite best efforts, I was unable to make the doc longer than the code. [Cherry-picked d36249284e79f33a897e3e53ea3967606f09c40c] --- .../dotty/tools/dotc/typer/RefChecks.scala | 55 +++++++++---------- tests/warn/ext-override.scala | 2 +- tests/warn/i16743.scala | 2 +- tests/warn/i22232.scala | 5 ++ tests/warn/i22705.scala | 28 ++++++++++ tests/warn/i22706.scala | 30 ++++++++++ tests/warn/i22727.scala | 14 +++++ 7 files changed, 106 insertions(+), 30 deletions(-) create mode 100644 tests/warn/i22705.scala create mode 100644 tests/warn/i22706.scala create mode 100644 tests/warn/i22727.scala diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 70daeb600708..3393378617d6 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -1033,14 +1033,24 @@ object RefChecks { end checkUnaryMethods /** Check that an extension method is not hidden, i.e., that it is callable as an extension method. + * + * For example, it is not possible to define a type-safe extension `contains` for `Set`, + * since for any parameter type, the existing `contains` method will compile and would be used. * * An extension method is hidden if it does not offer a parameter that is not subsumed * by the corresponding parameter of the member with the same name (or of all alternatives of an overload). * - * This check is suppressed if this method is an override. + * This check is suppressed if the method is an override. (Because the type of the receiver + * may be narrower in the override.) * - * For example, it is not possible to define a type-safe extension `contains` for `Set`, - * since for any parameter type, the existing `contains` method will compile and would be used. + * If the extension method is nullary, it is always hidden by a member of the same name. + * (Either the member is nullary, or the reference is taken as the eta-expansion of the member.) + * + * This check is in lieu of a more expensive use-site check that an application failed to use an extension. + * That check would account for accessibility and opacity. As a limitation, this check considers + * only public members for which corresponding method parameters are either both opaque types or both not. + * It is intended to warn if the receiver type from a third-party library has been augmented with a member + * that nullifies an existing extension. * * If the member has a leading implicit parameter list, then the extension method must also have * a leading implicit parameter list. The reason is that if the implicit arguments are inferred, @@ -1051,15 +1061,7 @@ object RefChecks { * If the member does not have a leading implicit parameter list, then the argument cannot be explicitly * supplied with `using`, as typechecking would fail. But the extension method may have leading implicit * parameters, which are necessarily supplied implicitly in the application. The first non-implicit - * parameters of the extension method must be distinguishable from the member parameters, as described. - * - * If the extension method is nullary, it is always hidden by a member of the same name. - * (Either the member is nullary, or the reference is taken as the eta-expansion of the member.) - * - * This check is in lieu of a more expensive use-site check that an application failed to use an extension. - * That check would account for accessibility and opacity. As a limitation, this check considers - * only public members, a target receiver that is not an alias, and corresponding method parameters - * that are either both opaque types or both not. + * parameters of the extension method must be distinguishable from the member parameters, as described above. */ def checkExtensionMethods(sym: Symbol)(using Context): Unit = if sym.is(Extension) then @@ -1067,26 +1069,23 @@ object RefChecks { def explicit = Applications.stripImplicit(tp.stripPoly, wildcardOnly = true) def hasImplicitParams = tp.stripPoly match { case mt: MethodType => mt.isImplicitMethod case _ => false } val explicitInfo = sym.info.explicit // consider explicit value params - val target = explicitInfo.firstParamTypes.head.typeSymbol.info // required for extension method, the putative receiver + val target0 = explicitInfo.firstParamTypes.head // required for extension method, the putative receiver + val target = target0.dealiasKeepOpaques.typeSymbol.info val methTp = explicitInfo.resultType // skip leading implicits and the "receiver" parameter + def memberMatchesMethod(member: Denotation) = + val memberIsImplicit = member.info.hasImplicitParams + val paramTps = + if memberIsImplicit then methTp.stripPoly.firstParamTypes + else methTp.explicit.firstParamTypes + inline def paramsCorrespond = + val memberParamTps = member.info.stripPoly.firstParamTypes + memberParamTps.corresponds(paramTps): (m, x) => + m.typeSymbol.denot.isOpaqueAlias == x.typeSymbol.denot.isOpaqueAlias && (x frozen_<:< m) + paramTps.isEmpty || memberIsImplicit && !methTp.hasImplicitParams || paramsCorrespond def hidden = target.nonPrivateMember(sym.name) .filterWithPredicate: member => - member.symbol.isPublic && { - val memberIsImplicit = member.info.hasImplicitParams - val paramTps = - if memberIsImplicit then methTp.stripPoly.firstParamTypes - else methTp.explicit.firstParamTypes - - paramTps.isEmpty || memberIsImplicit && !methTp.hasImplicitParams || { - val memberParamTps = member.info.stripPoly.firstParamTypes - !memberParamTps.isEmpty - && memberParamTps.lengthCompare(paramTps) == 0 - && memberParamTps.lazyZip(paramTps).forall: (m, x) => - m.typeSymbol.denot.isOpaqueAlias == x.typeSymbol.denot.isOpaqueAlias - && (x frozen_<:< m) - } - } + member.symbol.isPublic && memberMatchesMethod(member) .exists if sym.is(HasDefaultParams) then val getterDenot = diff --git a/tests/warn/ext-override.scala b/tests/warn/ext-override.scala index d08439e13c9a..32277083bd60 100644 --- a/tests/warn/ext-override.scala +++ b/tests/warn/ext-override.scala @@ -1,4 +1,4 @@ -//> using options -Xfatal-warnings +//> using options -Werror trait Foo[T]: extension (x: T) diff --git a/tests/warn/i16743.scala b/tests/warn/i16743.scala index e8860aeabaae..213e22ff4cb4 100644 --- a/tests/warn/i16743.scala +++ b/tests/warn/i16743.scala @@ -66,7 +66,7 @@ trait DungeonDweller: trait SadDungeonDweller: def f[A](x: Dungeon.IArray[A]) = 27 // x.length // just to confirm, length is not a member -trait Quote: +trait Quote: // see tests/warn/ext-override.scala type Tree <: AnyRef given TreeMethods: TreeMethods trait TreeMethods: diff --git a/tests/warn/i22232.scala b/tests/warn/i22232.scala index 79b8317a7329..f94e413920a2 100644 --- a/tests/warn/i22232.scala +++ b/tests/warn/i22232.scala @@ -23,6 +23,7 @@ object Upperbound3: object NonUpperbound1: opaque type MyString[+T] = String extension (arr: MyString[Byte]) def length: Int = 0 // nowarn + object NonUpperbound2: opaque type MyString[+T] = String extension [T <: MyString[Byte]](arr: T) def length2: Int = 0 // nowarn @@ -30,3 +31,7 @@ object NonUpperbound2: object NonUpperbound3: opaque type MyString[+T] = String extension [T](arr: T) def length: Int = 0 // nowarn + +object NonUpperbound4: + opaque type MyString = String + extension (arr: MyString) def length: Int = 0 // nowarn diff --git a/tests/warn/i22705.scala b/tests/warn/i22705.scala new file mode 100644 index 000000000000..d30c1b310201 --- /dev/null +++ b/tests/warn/i22705.scala @@ -0,0 +1,28 @@ +//> using options -Werror + +object Native { + class Obj: + def f: String = "F" +} + +object Types { + + opaque type Node = Native.Obj + + type S = Node + + object S: + def apply(): S = new Node + + extension (s: S) + def f: String = "S" +} + +import Types.* + +object Main { + def main(args: Array[String]): Unit = { + val v: S = S() + println(v.f) + } +} diff --git a/tests/warn/i22706.scala b/tests/warn/i22706.scala new file mode 100644 index 000000000000..5bd642020e1c --- /dev/null +++ b/tests/warn/i22706.scala @@ -0,0 +1,30 @@ +//> using options -Werror + +object Native { + class O { + def f: String = "F" + } + class M extends O +} + +object Types { + opaque type N = Native.O + opaque type GS = Native.M + + type S = N | GS + + object S: + def apply(): S = new N + + extension (s: S) + def f: String = "S" +} + +import Types.* + +object Main { + def main(args: Array[String]): Unit = { + val v: S = S() + println(v.f) + } +} diff --git a/tests/warn/i22727.scala b/tests/warn/i22727.scala new file mode 100644 index 000000000000..c7b1240c7e6b --- /dev/null +++ b/tests/warn/i22727.scala @@ -0,0 +1,14 @@ +//> using options -Werror + +object Main { + type IXY = (Int, Int) + + extension (xy: IXY) { + def map(f: Int => Int): (Int, Int) = (f(xy._1), f(xy._2)) + } + + def main(args: Array[String]): Unit = { + val a = (0, 1) + println(a) + } +} From 5d6a1510a1939d7f49eef34ade72969aa4a923ae Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Mon, 10 Mar 2025 08:03:33 -0700 Subject: [PATCH 189/505] No warn param of overriding method [Cherry-picked 825baf93209fba022dfa11ed2055849f7c622bcd] --- .../src/dotty/tools/dotc/transform/CheckUnused.scala | 1 + tests/warn/i15503e.scala | 4 ++-- tests/warn/i22742.scala | 10 ++++++++++ tests/warn/scala2-t11681.scala | 2 +- tests/warn/unused-params.scala | 4 ++-- 5 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 tests/warn/i22742.scala diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index 4b0e11c33759..005ce5ba3f64 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -573,6 +573,7 @@ object CheckUnused: end checkExplicit // begin if !infos.skip(m) + && !m.nextOverriddenSymbol.exists && !allowed then checkExplicit() diff --git a/tests/warn/i15503e.scala b/tests/warn/i15503e.scala index 2fafec339ac1..63a9dea163d4 100644 --- a/tests/warn/i15503e.scala +++ b/tests/warn/i15503e.scala @@ -70,10 +70,10 @@ package foo.test.i16865: trait Bar extends Foo object Ex extends Bar: - def fn(a: Int, b: Int): Int = b + 3 // warn + def fn(a: Int, b: Int): Int = b + 3 // no warn (override) object Ex2 extends Bar: - override def fn(a: Int, b: Int): Int = b + 3 // warn + override def fn(a: Int, b: Int): Int = b + 3 // no warn (override) final class alpha(externalName: String) extends StaticAnnotation // no warn annotation arg diff --git a/tests/warn/i22742.scala b/tests/warn/i22742.scala new file mode 100644 index 000000000000..0927d29e1a05 --- /dev/null +++ b/tests/warn/i22742.scala @@ -0,0 +1,10 @@ +//> using options -Wunused:all -Werror + +trait Foldable[F[_]]: + def foldLeft[A, B](fa: F[A], b: B)(f: (B, A) => B): B + +type Id[A] = A + +given foldableId: Foldable[Id] = + new Foldable[Id]: + def foldLeft[A, B](fa: Id[A], b: B)(f: (B, A) => B): B = b diff --git a/tests/warn/scala2-t11681.scala b/tests/warn/scala2-t11681.scala index 5d752777f64c..507b58bf2277 100644 --- a/tests/warn/scala2-t11681.scala +++ b/tests/warn/scala2-t11681.scala @@ -23,7 +23,7 @@ trait BadAPI extends InterFace { a } override def call(a: Int, - b: String, // warn now + b: String, // no warn (override) c: Double): Int = { println(c) a diff --git a/tests/warn/unused-params.scala b/tests/warn/unused-params.scala index 5ef339c942ac..3266f3957247 100644 --- a/tests/warn/unused-params.scala +++ b/tests/warn/unused-params.scala @@ -23,7 +23,7 @@ trait BadAPI extends InterFace { a } override def call(a: Int, - b: String, // warn + b: String, // no warn (override) c: Double): Int = { println(c) a @@ -136,7 +136,7 @@ trait BadMix { self: InterFace => } class Unequal { - override def equals(other: Any) = toString.nonEmpty // warn + override def equals(other: Any) = toString.nonEmpty // no warn (override) } class Seriously { From 81a38ab04e1f5aa4c64b62db07c7ebab4557e6e0 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Fri, 25 Apr 2025 08:42:14 +0200 Subject: [PATCH 190/505] chore: Fix compilation issue after backport conflict --- .../src/dotty/tools/repl/ReplDriver.scala | 2 +- tests/semanticdb/metac.expect | 244 +++++++++--------- 2 files changed, 120 insertions(+), 126 deletions(-) diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index f32b1fd5281c..cfbacf0589e1 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -547,7 +547,7 @@ class ReplDriver(settings: Array[String], try { val entries = flatten(jarFile) - val existingClass = entries.filter(_.ext.isClass).find(tryClassLoad(_).isDefined) + val existingClass = entries.filter(_.extension == "class").find(tryClassLoad(_).isDefined) if (existingClass.nonEmpty) out.println(s"The path '$path' cannot be loaded, it contains a classfile that already exists on the classpath: ${existingClass.get}") else inContext(state.context): diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index 4ea5386b4c50..4e3dee9d79a6 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -56,23 +56,23 @@ Synthetics => 3 entries Symbols: advanced/C# => class C [typeparam T ] extends Object { self: C[T] => +3 decls } -advanced/C#[T] => typeparam T +advanced/C#[T] => typeparam T advanced/C#``(). => primary ctor [typeparam T ](): C[T] advanced/C#t(). => method t => T advanced/HKClass# => class HKClass [typeparam F [typeparam T ] <: [U] =>> Tuple2[U, T]] extends Object { self: HKClass[F] => +3 decls } advanced/HKClass#[F] => typeparam F [typeparam T ] <: [U] =>> Tuple2[U, T] -advanced/HKClass#[F][T] => typeparam T -advanced/HKClass#[F][U] => typeparam U +advanced/HKClass#[F][T] => typeparam T +advanced/HKClass#[F][U] => typeparam U advanced/HKClass#``(). => primary ctor [typeparam F [typeparam T ] <: [U] =>> Tuple2[U, T]](): HKClass[F] -advanced/HKClass#``().[F][T] => typeparam T -advanced/HKClass#``().[F][U] => typeparam U +advanced/HKClass#``().[F][T] => typeparam T +advanced/HKClass#``().[F][U] => typeparam U advanced/HKClass#foo(). => method foo [typeparam T , typeparam U ](param x: F[T, U]): String advanced/HKClass#foo().(x) => param x: F[T, U] -advanced/HKClass#foo().[T] => typeparam T -advanced/HKClass#foo().[U] => typeparam U +advanced/HKClass#foo().[T] => typeparam T +advanced/HKClass#foo().[U] => typeparam U advanced/Structural# => class Structural extends Object { self: Structural => +6 decls } advanced/Structural#T# => trait T [typeparam A ] extends Object { self: T[A] => +4 decls } -advanced/Structural#T#[A] => typeparam A +advanced/Structural#T#[A] => typeparam A advanced/Structural#T#``(). => primary ctor [typeparam A ](): T[A] advanced/Structural#T#bar(). => method bar (param b: foo.B): Unit advanced/Structural#T#bar().(b) => param b: foo.B @@ -286,8 +286,8 @@ Symbols: annot/Alias. => final object Alias extends Object { self: Alias.type => +2 decls } annot/Alias.A# => type A = ClassAnnotation @param annot/Annotations# => @ClassAnnotation class Annotations [@TypeParameterAnnotation typeparam T ] extends Object { self: AnyRef & Annotations[T] => +6 decls } -annot/Annotations#S# => @TypeAnnotation type S -annot/Annotations#[T] => @TypeParameterAnnotation typeparam T +annot/Annotations#S# => @TypeAnnotation type S +annot/Annotations#[T] => @TypeParameterAnnotation typeparam T annot/Annotations#``(). => primary ctor [@TypeParameterAnnotation typeparam T ](@ParameterAnnotation param x: T): Annotations[T] annot/Annotations#``().(x) => @ParameterAnnotation param x: T annot/Annotations#field. => @FieldAnnotation val method field Int @@ -301,7 +301,7 @@ annot/B#throwing(). => @throws[Exception] method throwing => Nothing annot/B#x. => private[this] val method x Int annot/M. => @ObjectAnnotation final object M extends Object { self: M.type => +1 decls } annot/M.m(). => @MacroAnnotation macro m [typeparam TT ]: Int -annot/M.m().[TT] => typeparam TT +annot/M.m().[TT] => typeparam TT annot/T# => @TraitAnnotation trait T extends Object { self: T => +1 decls } annot/T#``(). => primary ctor (): T local0 => selfparam self: AnyRef @@ -394,10 +394,10 @@ example/Anonymous#bar2. => val method bar2 Bar example/Anonymous#foo. => val method foo Foo example/Anonymous#locally(). => method locally [typeparam A ](param x: A): A example/Anonymous#locally().(x) => param x: A -example/Anonymous#locally().[A] => typeparam A +example/Anonymous#locally().[A] => typeparam A example/Anonymous#m1(). => method m1 [typeparam T [type _ ]]: Nothing example/Anonymous#m1().[T] => typeparam T [type _ ] -example/Anonymous#m1().[T][_] => type _ +example/Anonymous#m1().[T][_] => type _ example/Anonymous#m2(). => method m2 => Map[_, List[_] forSome { type _ }] forSome { type _ } local0 => val local x: Function1[Int, Int] local1 => final class $anon extends Object with Foo { self: $anon => +1 decls } @@ -632,7 +632,7 @@ classes/C11#foo(). => inline macro foo => Int classes/C12# => class C12 extends Object { self: C12 => +8 decls } classes/C12#Context# => class Context extends Object { self: Context => +2 decls } classes/C12#Context#Expr# => type Expr [typeparam T ] -classes/C12#Context#Expr#[T] => typeparam T +classes/C12#Context#Expr#[T] => typeparam T classes/C12#Context#``(). => primary ctor (): Context classes/C12#``(). => primary ctor (): C12 classes/C12#foo1(). => macro foo1 (param x: Int): Int @@ -923,7 +923,7 @@ endmarkers/MultiCtor#``().(i) => val param i: Int endmarkers/MultiCtor#``(+1). => ctor (): MultiCtor endmarkers/MultiCtor#i. => val method i Int endmarkers/Stuff# => trait Stuff [typeparam A ] extends Object { self: Stuff[A] => +3 decls } -endmarkers/Stuff#[A] => typeparam A +endmarkers/Stuff#[A] => typeparam A endmarkers/Stuff#``(). => primary ctor [typeparam A ](): Stuff[A] endmarkers/Stuff#do(). => abstract method do => A endmarkers/TestObj. => final object TestObj extends Object { self: TestObj.type => +2 decls } @@ -1122,29 +1122,29 @@ _empty_/Enums.Directions.valueOf(). => method valueOf (param $name: String): Dir _empty_/Enums.Directions.valueOf().($name) => param $name: String _empty_/Enums.Directions.values(). => method values => Array[Directions] _empty_/Enums.Maybe# => abstract sealed enum class Maybe [covariant typeparam A ] extends Object with Enum { self: Maybe[A] => +2 decls } -_empty_/Enums.Maybe#[A] => covariant typeparam A +_empty_/Enums.Maybe#[A] => covariant typeparam A _empty_/Enums.Maybe#``(). => primary ctor [covariant typeparam A ](): Maybe[A] _empty_/Enums.Maybe. => final object Maybe extends Object { self: Maybe.type => +6 decls } _empty_/Enums.Maybe.Just# => final case enum class Just [covariant typeparam A ] extends Maybe[A] { self: Just[A] => +7 decls } -_empty_/Enums.Maybe.Just#[A] => covariant typeparam A +_empty_/Enums.Maybe.Just#[A] => covariant typeparam A _empty_/Enums.Maybe.Just#_1(). => method _1 => A _empty_/Enums.Maybe.Just#``(). => primary ctor [covariant typeparam A ](val param value: A): Just[A] _empty_/Enums.Maybe.Just#``().(value) => val param value: A _empty_/Enums.Maybe.Just#copy$default$1(). => method copy$default$1 [covariant typeparam A ]: A -_empty_/Enums.Maybe.Just#copy$default$1().[A] => typeparam A +_empty_/Enums.Maybe.Just#copy$default$1().[A] => typeparam A _empty_/Enums.Maybe.Just#copy(). => method copy [covariant typeparam A ](param value: A): Just[A] _empty_/Enums.Maybe.Just#copy().(value) => param value: A -_empty_/Enums.Maybe.Just#copy().[A] => typeparam A +_empty_/Enums.Maybe.Just#copy().[A] => typeparam A _empty_/Enums.Maybe.Just#ordinal(). => method ordinal => Int <: scala/reflect/Enum#ordinal(). _empty_/Enums.Maybe.Just#value. => val method value A _empty_/Enums.Maybe.Just. => final object Just extends Object { self: Just.type => +4 decls } _empty_/Enums.Maybe.Just.apply(). => method apply [typeparam A ](param value: A): Just[A] _empty_/Enums.Maybe.Just.apply().(value) => param value: A -_empty_/Enums.Maybe.Just.apply().[A] => typeparam A +_empty_/Enums.Maybe.Just.apply().[A] => typeparam A _empty_/Enums.Maybe.Just.toString(). => method toString => String <: scala/Any#toString(). _empty_/Enums.Maybe.Just.unapply(). => method unapply [typeparam A ](param x$1: Just[A]): Just[A] _empty_/Enums.Maybe.Just.unapply().(x$1) => param x$1: Just[A] -_empty_/Enums.Maybe.Just.unapply().[A] => typeparam A +_empty_/Enums.Maybe.Just.unapply().[A] => typeparam A _empty_/Enums.Maybe.None. => case val static enum method None Maybe[Nothing] _empty_/Enums.Maybe.fromOrdinal(). => method fromOrdinal (param ordinal: Int): Maybe[_] forSome { type _ } _empty_/Enums.Maybe.fromOrdinal().(ordinal) => param ordinal: Int @@ -1195,7 +1195,7 @@ _empty_/Enums.Suits.valueOf(). => method valueOf (param $name: String): Suits _empty_/Enums.Suits.valueOf().($name) => param $name: String _empty_/Enums.Suits.values(). => method values => Array[Suits] _empty_/Enums.Tag# => abstract sealed enum class Tag [typeparam A ] extends Object with Enum { self: Tag[A] => +2 decls } -_empty_/Enums.Tag#[A] => typeparam A +_empty_/Enums.Tag#[A] => typeparam A _empty_/Enums.Tag#``(). => primary ctor [typeparam A ](): Tag[A] _empty_/Enums.Tag. => final object Tag extends Object { self: Tag.type => +7 decls } _empty_/Enums.Tag.$values. => private[this] val method $values Array[Tag[_] forSome { type _ }] @@ -1226,33 +1226,33 @@ _empty_/Enums.WeekDays.valueOf(). => method valueOf (param $name: String): WeekD _empty_/Enums.WeekDays.valueOf().($name) => param $name: String _empty_/Enums.WeekDays.values(). => method values => Array[WeekDays] _empty_/Enums.`<:<`# => abstract sealed enum class <:< [contravariant typeparam A , typeparam B ] extends Object with Enum { self: <:<[A, B] => +3 decls } -_empty_/Enums.`<:<`#[A] => contravariant typeparam A -_empty_/Enums.`<:<`#[B] => typeparam B +_empty_/Enums.`<:<`#[A] => contravariant typeparam A +_empty_/Enums.`<:<`#[B] => typeparam B _empty_/Enums.`<:<`#``(). => primary ctor [contravariant typeparam A , typeparam B ](): <:<[A, B] _empty_/Enums.`<:<`. => final object <:< extends Object { self: <:<.type => +6 decls } _empty_/Enums.`<:<`.Refl# => final case enum class Refl [typeparam C ] extends <:<[C, C] { self: Refl[C] => +4 decls } -_empty_/Enums.`<:<`.Refl#[C] => typeparam C +_empty_/Enums.`<:<`.Refl#[C] => typeparam C _empty_/Enums.`<:<`.Refl#``(). => primary ctor [typeparam C ](): Refl[C] _empty_/Enums.`<:<`.Refl#copy(). => method copy [typeparam C ](): Refl[C] -_empty_/Enums.`<:<`.Refl#copy().[C] => typeparam C +_empty_/Enums.`<:<`.Refl#copy().[C] => typeparam C _empty_/Enums.`<:<`.Refl#ordinal(). => method ordinal => Int <: scala/reflect/Enum#ordinal(). _empty_/Enums.`<:<`.Refl. => final object Refl extends Object { self: Refl.type => +4 decls } _empty_/Enums.`<:<`.Refl.apply(). => method apply [typeparam C ](): Refl[C] -_empty_/Enums.`<:<`.Refl.apply().[C] => typeparam C +_empty_/Enums.`<:<`.Refl.apply().[C] => typeparam C _empty_/Enums.`<:<`.Refl.toString(). => method toString => String <: scala/Any#toString(). _empty_/Enums.`<:<`.Refl.unapply(). => method unapply [typeparam C ](param x$1: Refl[C]): true _empty_/Enums.`<:<`.Refl.unapply().(x$1) => param x$1: Refl[C] -_empty_/Enums.`<:<`.Refl.unapply().[C] => typeparam C +_empty_/Enums.`<:<`.Refl.unapply().[C] => typeparam C _empty_/Enums.`<:<`.`given_<:<_T_T`(). => final implicit given method given_<:<_T_T [typeparam T ]: <:<[T, T] -_empty_/Enums.`<:<`.`given_<:<_T_T`().[T] => typeparam T +_empty_/Enums.`<:<`.`given_<:<_T_T`().[T] => typeparam T _empty_/Enums.`<:<`.fromOrdinal(). => method fromOrdinal (param ordinal: Int): <:<[_, _] forSome { type _ ; type _ } _empty_/Enums.`<:<`.fromOrdinal().(ordinal) => param ordinal: Int _empty_/Enums.some1. => val method some1 Option[Int] _empty_/Enums.unwrap(). => method unwrap [typeparam A , typeparam B ](param opt: Option[A])(implicit given param ev: <:<[A, Option[B]]): Option[B] _empty_/Enums.unwrap().(ev) => implicit given param ev: <:<[A, Option[B]] _empty_/Enums.unwrap().(opt) => param opt: Option[A] -_empty_/Enums.unwrap().[A] => typeparam A -_empty_/Enums.unwrap().[B] => typeparam B +_empty_/Enums.unwrap().[A] => typeparam A +_empty_/Enums.unwrap().[B] => typeparam B local0 => param x: Option[B] Occurrences: @@ -1525,7 +1525,7 @@ Symbols: ext/DeckUsage. => final object DeckUsage extends Object { self: DeckUsage.type => +2 decls } ext/DeckUsage.deck. => val method deck Deck ext/Extension$package. => final package object ext extends Object { self: ext.type { opaque type Deck } => +9 decls } -ext/Extension$package.Deck# => opaque type Deck +ext/Extension$package.Deck# => opaque type Deck ext/Extension$package.Deck. => final object Deck extends Object { self: Deck.type => +2 decls } ext/Extension$package.Deck.fooSize(). => method fooSize (param data: Deck): Int ext/Extension$package.Deck.fooSize().(data) => param data: Deck @@ -1539,18 +1539,18 @@ ext/Extension$package.foo().(s) => param s: String ext/Extension$package.readInto(). => method readInto [typeparam T ](param s: String)(implicit given param x$2: Read[T]): Option[T] ext/Extension$package.readInto().(s) => param s: String ext/Extension$package.readInto().(x$2) => implicit given param x$2: Read[T] -ext/Extension$package.readInto().[T] => typeparam T +ext/Extension$package.readInto().[T] => typeparam T ext/Functor# => trait Functor [typeparam F [type _ ]] extends Object { self: Functor[F] => +3 decls } ext/Functor#[F] => typeparam F [type _ ] -ext/Functor#[F][_] => type _ +ext/Functor#[F][_] => type _ ext/Functor#``(). => primary ctor [typeparam F [type _ ]](): Functor[F] ext/Functor#map(). => abstract method map [typeparam T , typeparam U ](param t: F[T])(param f: Function1[T, U]): F[U] ext/Functor#map().(f) => param f: Function1[T, U] ext/Functor#map().(t) => param t: F[T] -ext/Functor#map().[T] => typeparam T -ext/Functor#map().[U] => typeparam U +ext/Functor#map().[T] => typeparam T +ext/Functor#map().[U] => typeparam U ext/Read# => trait Read [covariant typeparam T ] extends Object { self: Read[T] => +3 decls } -ext/Read#[T] => covariant typeparam T +ext/Read#[T] => covariant typeparam T ext/Read#``(). => primary ctor [covariant typeparam T ](): Read[T] ext/Read#fromString(). => abstract method fromString (param s: String): Option[T] ext/Read#fromString().(s) => param s: String @@ -1731,7 +1731,7 @@ Synthetics => 3 entries Symbols: a/b/Givens. => final object Givens extends Object { self: Givens.type => +13 decls } a/b/Givens.Monoid# => trait Monoid [typeparam A ] extends Object { self: Monoid[A] => +4 decls } -a/b/Givens.Monoid#[A] => typeparam A +a/b/Givens.Monoid#[A] => typeparam A a/b/Givens.Monoid#``(). => primary ctor [typeparam A ](): Monoid[A] a/b/Givens.Monoid#combine(). => abstract method combine (param x: A)(param y: A): A a/b/Givens.Monoid#combine().(x) => param x: A @@ -1739,7 +1739,7 @@ a/b/Givens.Monoid#combine().(y) => param y: A a/b/Givens.Monoid#empty(). => abstract method empty => A a/b/Givens.foo(). => method foo [typeparam A ](implicit given param A: Monoid[A]): A a/b/Givens.foo().(A) => implicit given param A: Monoid[A] -a/b/Givens.foo().[A] => typeparam A +a/b/Givens.foo().[A] => typeparam A a/b/Givens.given_Monoid_String. => final implicit given object given_Monoid_String extends Object with Monoid[String] { self: given_Monoid_String.type => +3 decls } a/b/Givens.given_Monoid_String.combine(). => method combine (param x: String)(param y: String): String <: a/b/Givens.Monoid#combine(). a/b/Givens.given_Monoid_String.combine().(x) => param x: String @@ -1754,13 +1754,13 @@ a/b/Givens.int2String#apply().(x) => param x: Int a/b/Givens.int2String(). => final implicit given inline macro int2String => int2String a/b/Givens.sayGoodbye(). => method sayGoodbye [typeparam B ](param any: B): String a/b/Givens.sayGoodbye().(any) => param any: B -a/b/Givens.sayGoodbye().[B] => typeparam B +a/b/Givens.sayGoodbye().[B] => typeparam B a/b/Givens.sayHello(). => method sayHello [typeparam A ](param any: A): String a/b/Givens.sayHello().(any) => param any: A -a/b/Givens.sayHello().[A] => typeparam A +a/b/Givens.sayHello().[A] => typeparam A a/b/Givens.saySoLong(). => method saySoLong [typeparam B ](param any: B): String a/b/Givens.saySoLong().(any) => param any: B -a/b/Givens.saySoLong().[B] => typeparam B +a/b/Givens.saySoLong().[B] => typeparam B a/b/Givens.soLong1. => val method soLong1 String Occurrences: @@ -1868,7 +1868,7 @@ example/ImplicitConversion#tuple. => val method tuple Tuple2[Int, Int] example/ImplicitConversion#x. => val method x Int example/ImplicitConversion. => final object ImplicitConversion extends Object { self: ImplicitConversion.type => +6 decls } example/ImplicitConversion.newAny2stringadd# => final implicit class newAny2stringadd [typeparam A ] extends AnyVal { self: newAny2stringadd[A] => +4 decls } -example/ImplicitConversion.newAny2stringadd#[A] => typeparam A +example/ImplicitConversion.newAny2stringadd#[A] => typeparam A example/ImplicitConversion.newAny2stringadd#`+`(). => method + (param other: String): String example/ImplicitConversion.newAny2stringadd#`+`().(other) => param other: String example/ImplicitConversion.newAny2stringadd#``(). => primary ctor [typeparam A ](param self: A): newAny2stringadd[A] @@ -1876,7 +1876,7 @@ example/ImplicitConversion.newAny2stringadd#``().(self) => param self: A example/ImplicitConversion.newAny2stringadd#self. => private val method self A example/ImplicitConversion.newAny2stringadd(). => final implicit method newAny2stringadd [typeparam A ](param self: A): newAny2stringadd[A] example/ImplicitConversion.newAny2stringadd().(self) => param self: A -example/ImplicitConversion.newAny2stringadd().[A] => typeparam A +example/ImplicitConversion.newAny2stringadd().[A] => typeparam A example/ImplicitConversion.newAny2stringadd. => final object newAny2stringadd extends Object { self: newAny2stringadd.type => +2 decls } Occurrences: @@ -2089,7 +2089,7 @@ givens/InventedNames$package.given_Double(). => final implicit given method give givens/InventedNames$package.given_Double().(x$1) => implicit given param x$1: Int givens/InventedNames$package.given_Float. => final implicit lazy val given method given_Float Float givens/InventedNames$package.given_List_T(). => final implicit given method given_List_T [typeparam T ]: List[T] -givens/InventedNames$package.given_List_T().[T] => typeparam T +givens/InventedNames$package.given_List_T().[T] => typeparam T givens/InventedNames$package.given_String. => final implicit lazy val given method given_String String givens/InventedNames$package.given_X. => final implicit given object given_X extends Object with X { self: given_X.type => +2 decls } givens/InventedNames$package.given_X.doX(). => method doX => Int <: givens/X#doX(). @@ -2101,11 +2101,11 @@ givens/InventedNames$package.given_Y#x$1. => protected implicit val given method givens/InventedNames$package.given_Y(). => final implicit given method given_Y (implicit given param x$1: X): given_Y givens/InventedNames$package.given_Y().(x$1) => implicit given param x$1: X givens/InventedNames$package.given_Z_T# => implicit given class given_Z_T [typeparam T ] extends Object with Z[T] { self: given_Z_T[T] => +3 decls } -givens/InventedNames$package.given_Z_T#[T] => typeparam T +givens/InventedNames$package.given_Z_T#[T] => typeparam T givens/InventedNames$package.given_Z_T#``(). => primary ctor [typeparam T ](): given_Z_T[T] givens/InventedNames$package.given_Z_T#doZ(). => method doZ => List[T] <: givens/Z#doZ(). givens/InventedNames$package.given_Z_T(). => final implicit given method given_Z_T [typeparam T ]: given_Z_T[T] -givens/InventedNames$package.given_Z_T().[T] => typeparam T +givens/InventedNames$package.given_Z_T().[T] => typeparam T givens/InventedNames$package.intValue. => final implicit lazy val given method intValue Int givens/InventedNames$package.x. => val method x given_X.type givens/InventedNames$package.y. => val method y given_Y @@ -2117,7 +2117,7 @@ givens/Y# => trait Y extends Object { self: Y => +2 decls } givens/Y#``(). => primary ctor (): Y givens/Y#doY(). => abstract method doY => String givens/Z# => trait Z [typeparam T ] extends Object { self: Z[T] => +3 decls } -givens/Z#[T] => typeparam T +givens/Z#[T] => typeparam T givens/Z#``(). => primary ctor [typeparam T ](): Z[T] givens/Z#doZ(). => abstract method doZ => List[T] @@ -2292,7 +2292,7 @@ Symbols: example/Local# => class Local extends Object { self: Local => +2 decls } example/Local#``(). => primary ctor (): Local example/Local#a(). => method a (): Int -local0 => typeparam A +local0 => typeparam A local1 => param a: A local2 => local id: [typeparam A ](param a: A): A @@ -2357,10 +2357,10 @@ example/MatchType$package.Concat# => type Concat [typeparam Xs <: Tuple, covari example/MatchType$package.Concat#[Xs] => typeparam Xs <: Tuple example/MatchType$package.Concat#[Ys] => covariant typeparam Ys <: Tuple example/MatchType$package.Elem# => type Elem [typeparam X ] = X match { String => Char, Array[t] => t, Iterable[t] => t } -example/MatchType$package.Elem#[X] => typeparam X -local0 => type t -local1 => type t -local2 => type x +example/MatchType$package.Elem#[X] => typeparam X +local0 => type t +local1 => type t +local2 => type x local3 => type xs <: Tuple Occurrences: @@ -2600,11 +2600,11 @@ Occurrences => 156 entries Symbols: example/Methods# => class Methods [typeparam T ] extends Object { self: Methods[T] => +44 decls } example/Methods#AList# => type AList [typeparam T ] = List[T] -example/Methods#AList#[T] => typeparam T +example/Methods#AList#[T] => typeparam T example/Methods#List# => class List [typeparam T ] extends Object { self: List[T] => +2 decls } -example/Methods#List#[T] => typeparam T +example/Methods#List#[T] => typeparam T example/Methods#List#``(). => primary ctor [typeparam T ](): List[T] -example/Methods#[T] => typeparam T +example/Methods#[T] => typeparam T example/Methods#``(). => primary ctor [typeparam T ](): Methods[T] example/Methods#`m8().`(). => method m8(). (): Nothing example/Methods#`m9().`# => class m9(). extends Object { self: m9(). => +1 decls } @@ -2632,7 +2632,7 @@ example/Methods#m7(). => method m7 [typeparam U ](param c: Methods[T], param l: example/Methods#m7().(c) => param c: Methods[T] example/Methods#m7().(evidence$1) => implicit param evidence$1: Ordering[U] example/Methods#m7().(l) => param l: List[U] -example/Methods#m7().[U] => typeparam U +example/Methods#m7().[U] => typeparam U example/Methods#m9(). => method m9 (param x: m9().): Nothing example/Methods#m9().(x) => param x: m9(). example/Methods#m10(). => method m10 (param x: List[T]): Nothing @@ -2992,18 +2992,18 @@ Occurrences => 18 entries Symbols: _empty_/NewModifiers$package. => final package object _empty_ extends Object { self: _empty_.type { opaque type OpaqueB } => +2 decls } -_empty_/NewModifiers$package.OpaqueB# => opaque type OpaqueB +_empty_/NewModifiers$package.OpaqueB# => opaque type OpaqueB _empty_/NewModifiers. => final object NewModifiers extends Object { self: NewModifiers.type { opaque type A } => +3 decls } -_empty_/NewModifiers.A# => opaque type A +_empty_/NewModifiers.A# => opaque type A _empty_/NewModifiers.foo. => val inline method foo "foo" _empty_/NewModifiersClass# => opaque class NewModifiersClass extends Object { self: Any { opaque type C } & NewModifiersClass => +5 decls } -_empty_/NewModifiersClass#C# => opaque type C +_empty_/NewModifiersClass#C# => opaque type C _empty_/NewModifiersClass#Nested# => opaque class Nested extends Object { self: Any { opaque type NestedOpaque } & Nested => +2 decls } -_empty_/NewModifiersClass#Nested#NestedOpaque# => opaque type NestedOpaque +_empty_/NewModifiersClass#Nested#NestedOpaque# => opaque type NestedOpaque _empty_/NewModifiersClass#Nested#``(). => primary ctor (): Nested _empty_/NewModifiersClass#``(). => primary ctor (): NewModifiersClass _empty_/NewModifiersTrait# => opaque trait NewModifiersTrait extends Object { self: Any { opaque type D } & NewModifiersTrait => +2 decls } -_empty_/NewModifiersTrait#D# => opaque type D +_empty_/NewModifiersTrait#D# => opaque type D _empty_/NewModifiersTrait#``(). => primary ctor (): NewModifiersTrait Occurrences: @@ -3091,13 +3091,13 @@ Occurrences => 49 entries Symbols: prefixes/C# => class C extends Object { self: C => +6 decls } prefixes/C#N. => final object N extends Object { self: N.type => +2 decls } -prefixes/C#N.U# => type U -prefixes/C#T# => type T +prefixes/C#N.U# => type U +prefixes/C#T# => type T prefixes/C#``(). => primary ctor (): C prefixes/C#k1(). => method k1 => U prefixes/C#m1(). => method m1 => T prefixes/M. => final object M extends Object { self: M.type => +3 decls } -prefixes/M.T# => type T +prefixes/M.T# => type T prefixes/M.n1(). => method n1 => T prefixes/O. => final object O extends C { self: O.type => +2 decls } prefixes/O.o1(). => method o1 => O.this.T @@ -3174,13 +3174,13 @@ Synthetics => 3 entries Symbols: example/C# => class C extends Object { self: C => +3 decls } -example/C#T1# => type T1 -example/C#T2# => type T2 +example/C#T1# => type T1 +example/C#T2# => type T2 example/C#``(). => primary ctor (): C example/PickOneRefinement_1# => class PickOneRefinement_1 [typeparam S <: SpecialRefinement { abstract method pickOne [typeparam T ](param as: T*): Option[String] }] extends Object { self: PickOneRefinement_1[S] => +3 decls } example/PickOneRefinement_1#[S] => typeparam S <: SpecialRefinement { abstract method pickOne [typeparam T ](param as: T*): Option[String] } example/PickOneRefinement_1#[S](as) => param as: T* -example/PickOneRefinement_1#[S][T] => typeparam T +example/PickOneRefinement_1#[S][T] => typeparam T example/PickOneRefinement_1#``(). => primary ctor [typeparam S <: SpecialRefinement { abstract method pickOne [typeparam T ](param as: T*): Option[String] }](): PickOneRefinement_1[S] example/PickOneRefinement_1#run(). => method run (param s: S, param as: String*): Option[String] example/PickOneRefinement_1#run().(as) => param as: String* @@ -3189,7 +3189,7 @@ example/PolyHolder# => trait PolyHolder extends Object { self: PolyHolder => +2 example/PolyHolder#``(). => primary ctor (): PolyHolder example/PolyHolder#foo(). => abstract method foo [typeparam T ](param t: T): Any example/PolyHolder#foo().(t) => param t: T -example/PolyHolder#foo().[T] => typeparam T +example/PolyHolder#foo().[T] => typeparam T example/RecOrRefined$package. => final package object example extends Object { self: example.type => +9 decls } example/RecOrRefined$package.C2# => type C2 = C { type T2 = T1 <: example/C#T2#; type T1 <: example/C#T1# } example/RecOrRefined$package.Person# => type Person = Record { abstract val method age Int; abstract val method name String } @@ -3203,9 +3203,9 @@ example/RecOrRefined$package.m4(). => method m4 (param x: PolyHolder { abstract example/RecOrRefined$package.m4().(x) => param x: PolyHolder { abstract method foo [typeparam T ](param t: T): T <: example/PolyHolder#foo(). } example/RecOrRefined$package.m5(). => method m5 [typeparam Z ](param x: Int): PolyHolder { abstract method foo [typeparam T ](param t: T): T <: example/PolyHolder#foo(). } example/RecOrRefined$package.m5().(x) => param x: Int -example/RecOrRefined$package.m5().[Z] => typeparam Z +example/RecOrRefined$package.m5().[Z] => typeparam Z example/RecOrRefined$package.m6# => type m6 [typeparam X ] = PolyHolder { abstract method foo [typeparam T ](param t: T): T <: example/PolyHolder#foo(). } -example/RecOrRefined$package.m6#[X] => typeparam X +example/RecOrRefined$package.m6#[X] => typeparam X example/Record# => class Record extends Object with Selectable { self: Record => +4 decls } example/Record#``(). => primary ctor (param elems: Tuple2[String, Any]*): Record example/Record#``().(elems) => param elems: Tuple2[String, Any]* @@ -3217,9 +3217,9 @@ example/SpecialRefinement# => trait SpecialRefinement extends Object { self: Spe example/SpecialRefinement#``(). => primary ctor (): SpecialRefinement example/SpecialRefinement#pickOne(). => abstract method pickOne [typeparam T ](param as: T*): Option[Any] example/SpecialRefinement#pickOne().(as) => param as: T* -example/SpecialRefinement#pickOne().[T] => typeparam T +example/SpecialRefinement#pickOne().[T] => typeparam T local0 => abstract method pickOne [typeparam T ](param as: T*): Option[String] -local1 => typeparam T +local1 => typeparam T local2 => param as: T* local3 => abstract method pickOne [typeparam T ](param as: T*): Option[String] <: example/SpecialRefinement#pickOne(). local4 => abstract val method x Int @@ -3227,14 +3227,14 @@ local5 => abstract val method x Int local6 => abstract method y => Int local7 => abstract val method x Int local8 => abstract method y => Int -local9 => type z -local10 => typeparam T +local9 => type z +local10 => typeparam T local11 => param t: T local12 => abstract method foo [typeparam T ](param t: T): T <: example/PolyHolder#foo(). -local13 => typeparam T +local13 => typeparam T local14 => param t: T local15 => abstract method foo [typeparam T ](param t: T): T <: example/PolyHolder#foo(). -local16 => typeparam T +local16 => typeparam T local17 => param t: T local18 => abstract method foo [typeparam T ](param t: T): T <: example/PolyHolder#foo(). local19 => abstract val method name String @@ -3456,7 +3456,6 @@ Text => empty Language => Scala Symbols => 12 entries Occurrences => 33 entries -Diagnostics => 1 entries Synthetics => 4 entries Symbols: @@ -3508,11 +3507,6 @@ Occurrences: [20:4..20:13): scalameta -> scala/reflect/Selectable#selectDynamic(). [21:4..21:19): StructuralTypes -> example/StructuralTypes. -Diagnostics: -[14:20..14:23): [warning] Alphanumeric method foo is not declared infix; it should not be used as infix operator. -Instead, use method syntax .foo(...) or backticked identifier `foo`. -The latter can be rewritten automatically under -rewrite -source 3.4-migration. - Synthetics: [12:2..12:6):user => reflectiveSelectable(*) [13:2..13:6):user => reflectiveSelectable(*) @@ -3547,7 +3541,7 @@ example/Synthetic#Contexts.m4(). => method m4 => Nothing example/Synthetic#F# => class F extends Object { self: F => +1 decls } example/Synthetic#F#``(). => primary ctor (): F example/Synthetic#J# => class J [typeparam T ] extends Object { self: J[T] => +4 decls } -example/Synthetic#J#[T] => typeparam T +example/Synthetic#J#[T] => typeparam T example/Synthetic#J#``(). => primary ctor [typeparam T ]()(implicit param evidence$1: Manifest[T]): J[T] example/Synthetic#J#``().(evidence$1) => implicit param evidence$1: Manifest[T] example/Synthetic#J#arr. => val method arr Array[T] @@ -4256,11 +4250,11 @@ Occurrences => 18 entries Symbols: _empty_/Test_depmatch. => final object Test_depmatch extends Object { self: Test_depmatch.type => +4 decls } _empty_/Test_depmatch.Bar# => type Bar [typeparam T ] = T match { Unit => Unit } -_empty_/Test_depmatch.Bar#[T] => typeparam T +_empty_/Test_depmatch.Bar#[T] => typeparam T _empty_/Test_depmatch.Foo# => type Foo = Int { type U } _empty_/Test_depmatch.baz(). => inline macro baz (param foo: Foo): Unit _empty_/Test_depmatch.baz().(foo) => param foo: Foo -local0 => type U +local0 => type U local1 => val local v: Bar[foo.U] Occurrences: @@ -4316,7 +4310,7 @@ Occurrences => 33 entries Symbols: exports/example/Codec# => trait Codec [typeparam T ] extends Object with Decoder[T] with Encoder[T] { self: Codec[T] => +6 decls } -exports/example/Codec#[T] => typeparam T +exports/example/Codec#[T] => typeparam T exports/example/Codec#``(). => primary ctor [typeparam T ](param decode: Decoder[T], param encode: Encoder[T]): Codec[T] exports/example/Codec#``().(decode) => param decode: Decoder[T] exports/example/Codec#``().(encode) => param encode: Encoder[T] @@ -4327,12 +4321,12 @@ exports/example/Codec#encode(). => final method encode (param t: T): Array[Byte] exports/example/Codec#encode().(t) => param t: T exports/example/Codec#encode. => private[this] val method encode Encoder[T] exports/example/Decoder# => trait Decoder [covariant typeparam T ] extends Object { self: Decoder[T] => +3 decls } -exports/example/Decoder#[T] => covariant typeparam T +exports/example/Decoder#[T] => covariant typeparam T exports/example/Decoder#``(). => primary ctor [covariant typeparam T ](): Decoder[T] exports/example/Decoder#decode(). => abstract method decode (param a: Array[Byte]): T exports/example/Decoder#decode().(a) => param a: Array[Byte] exports/example/Encoder# => trait Encoder [contravariant typeparam T ] extends Object { self: Encoder[T] => +3 decls } -exports/example/Encoder#[T] => contravariant typeparam T +exports/example/Encoder#[T] => contravariant typeparam T exports/example/Encoder#``(). => primary ctor [contravariant typeparam T ](): Encoder[T] exports/example/Encoder#encode(). => abstract method encode (param t: T): Array[Byte] exports/example/Encoder#encode().(t) => param t: T @@ -4386,11 +4380,11 @@ Occurrences => 5 entries Symbols: exports/`exports-package$package`. => final package object exports extends Object { self: exports.type => +4 decls } exports/`exports-package$package`.Codec# => final type Codec [typeparam T ] = Codec[T] -exports/`exports-package$package`.Codec#[T] => typeparam T +exports/`exports-package$package`.Codec#[T] => typeparam T exports/`exports-package$package`.Decoder# => final type Decoder [typeparam T ] = Decoder[T] -exports/`exports-package$package`.Decoder#[T] => typeparam T +exports/`exports-package$package`.Decoder#[T] => typeparam T exports/`exports-package$package`.Encoder# => final type Encoder [typeparam T ] = Encoder[T] -exports/`exports-package$package`.Encoder#[T] => typeparam T +exports/`exports-package$package`.Encoder#[T] => typeparam T Occurrences: [0:8..0:15): exports <- exports/ @@ -4432,35 +4426,35 @@ Occurrences => 54 entries Symbols: hk/EitherMonad# => class EitherMonad [typeparam T ] extends Object with Monad[[E] =>> Either[T, E]] { self: EitherMonad[T] => +2 decls } -hk/EitherMonad#[E] => typeparam E -hk/EitherMonad#[T] => typeparam T +hk/EitherMonad#[E] => typeparam E +hk/EitherMonad#[T] => typeparam T hk/EitherMonad#``(). => primary ctor [typeparam T ](): EitherMonad[T] -hk/EitherMonad#``().[E] => typeparam E +hk/EitherMonad#``().[E] => typeparam E hk/Monad# => trait Monad [typeparam M [type _ ]] extends Object { self: Monad[M] => +4 decls } hk/Monad#[M] => typeparam M [type _ ] -hk/Monad#[M][_] => type _ +hk/Monad#[M][_] => type _ hk/Monad#``(). => primary ctor [typeparam M [type _ ]](): Monad[M] hk/Monad#flatMap(). => method flatMap [typeparam A , typeparam B ](param m: M[A])(param f: Function1[A, M[B]]): M[B] hk/Monad#flatMap().(f) => param f: Function1[A, M[B]] hk/Monad#flatMap().(m) => param m: M[A] -hk/Monad#flatMap().[A] => typeparam A -hk/Monad#flatMap().[B] => typeparam B +hk/Monad#flatMap().[A] => typeparam A +hk/Monad#flatMap().[B] => typeparam B hk/Monad#pure(). => method pure [typeparam A ](param a: A): M[A] hk/Monad#pure().(a) => param a: A -hk/Monad#pure().[A] => typeparam A +hk/Monad#pure().[A] => typeparam A hk/hk$package. => final package object hk extends Object { self: hk.type => +5 decls } hk/hk$package.Id# => type Id [typeparam A ] = A -hk/hk$package.Id#[A] => typeparam A +hk/hk$package.Id#[A] => typeparam A hk/hk$package.MapEither# => type MapEither [typeparam K ] = [L] =>> [R] =>> Map[K, Either[L, R]] -hk/hk$package.MapEither#[K] => typeparam K -hk/hk$package.MapEither#[L] => typeparam L -hk/hk$package.MapEither#[R] => typeparam R +hk/hk$package.MapEither#[K] => typeparam K +hk/hk$package.MapEither#[L] => typeparam L +hk/hk$package.MapEither#[R] => typeparam R hk/hk$package.MapKV# => type MapKV [typeparam K ] = [V] =>> Map[K, V] -hk/hk$package.MapKV#[K] => typeparam K -hk/hk$package.MapKV#[V] => typeparam V +hk/hk$package.MapKV#[K] => typeparam K +hk/hk$package.MapKV#[V] => typeparam V hk/hk$package.MapV# => type MapV [type _ ] = [V] =>> Map[String, V] -hk/hk$package.MapV#[V] => typeparam V -hk/hk$package.MapV#[_] => type _ +hk/hk$package.MapV#[V] => typeparam V +hk/hk$package.MapV#[_] => type _ Occurrences: [0:8..0:10): hk <- hk/ @@ -4800,11 +4794,11 @@ _empty_/Concrete#``(). => primary ctor (): Concrete _empty_/Concrete#nullary2(). => method nullary2 => Int <: _empty_/NullaryTest#nullary2(). _empty_/Concrete#nullary3(). => method nullary3 => List[Int] <: _empty_/NullaryTest#nullary3(). _empty_/NullaryTest# => abstract class NullaryTest [typeparam T , typeparam m [typeparam s ]] extends Object { self: NullaryTest[T, m] => +9 decls } -_empty_/NullaryTest#[T] => typeparam T +_empty_/NullaryTest#[T] => typeparam T _empty_/NullaryTest#[m] => typeparam m [typeparam s ] -_empty_/NullaryTest#[m][s] => typeparam s +_empty_/NullaryTest#[m][s] => typeparam s _empty_/NullaryTest#``(). => primary ctor [typeparam T , typeparam m [typeparam s ]](): NullaryTest[T, m] -_empty_/NullaryTest#``().[m][s] => typeparam s +_empty_/NullaryTest#``().[m][s] => typeparam s _empty_/NullaryTest#nullary(). => method nullary => String _empty_/NullaryTest#nullary2(). => abstract method nullary2 => T _empty_/NullaryTest#nullary3(). => abstract method nullary3 => m[T] @@ -5008,9 +5002,9 @@ flags/p/package.AA#x. => private[this] val method x Int flags/p/package.AA#y. => val method y Int flags/p/package.AA#z(). => var method z Int flags/p/package.C# => abstract class C [covariant typeparam T , contravariant typeparam U , typeparam V ] extends Object { self: C[T, U, V] => +10 decls } -flags/p/package.C#[T] => covariant typeparam T -flags/p/package.C#[U] => contravariant typeparam U -flags/p/package.C#[V] => typeparam V +flags/p/package.C#[T] => covariant typeparam T +flags/p/package.C#[U] => contravariant typeparam U +flags/p/package.C#[V] => typeparam V flags/p/package.C#``(). => primary ctor [covariant typeparam T , contravariant typeparam U , typeparam V ](param x: T, param y: U, param z: V): C[T, U, V] flags/p/package.C#``().(x) => param x: T flags/p/package.C#``().(y) => param y: U @@ -5023,11 +5017,11 @@ flags/p/package.C#x. => private[this] val method x T flags/p/package.C#y. => private[this] val method y U flags/p/package.C#z. => private[this] val method z V flags/p/package.S# => class S [@specialized typeparam T ] extends Object { self: S[T] => +2 decls } -flags/p/package.S#[T] => @specialized typeparam T +flags/p/package.S#[T] => @specialized typeparam T flags/p/package.S#``(). => primary ctor [@specialized typeparam T ](): S[T] flags/p/package.T1# => type T1 = Int flags/p/package.T2# => type T2 [typeparam T ] = S[T] -flags/p/package.T2#[T] => typeparam T +flags/p/package.T2#[T] => typeparam T flags/p/package.U# => type U <: Int flags/p/package.V# => type V >: Int flags/p/package.X. => final case object X extends Object with Product with Serializable { self: X.type => +1 decls } @@ -5038,14 +5032,14 @@ flags/p/package.Z#``(). => primary ctor (): Z flags/p/package.`y_=`(). => protected var method y_= (param x$1: Int): Unit flags/p/package.`y_=`().(x$1) => param x$1: Int flags/p/package.m(). => macro m [typeparam TT ]: Int -flags/p/package.m().[TT] => typeparam TT +flags/p/package.m().[TT] => typeparam TT flags/p/package.x. => private[flags/p/] lazy val method x Int flags/p/package.xs1. => val method xs1 Nothing flags/p/package.y(). => protected implicit var method y Int flags/p/package.z(). => method z (param pp: Int): Int flags/p/package.z().(pp) => param pp: Int local0 => val local xs2: Nothing -local1 => type t +local1 => type t Occurrences: [0:8..0:13): flags <- flags/ @@ -5160,7 +5154,7 @@ local3 => final class $anon extends Object { self: $anon => +2 decls } local5 => final class $anon extends M with N { self: $anon => +1 decls } local7 => method k => Int local8 => final class $anon extends M with N { self: $anon => +2 decls } -local10 => typeparam T +local10 => typeparam T local11 => type L [typeparam T ] = List[T] types/B# => class B extends Object { self: B => +1 decls } types/B#``(). => primary ctor (): B @@ -5205,7 +5199,7 @@ types/Test.C#ClassInfoType2# => class ClassInfoType2 extends B { self: ClassInfo types/Test.C#ClassInfoType2#``(). => primary ctor (): ClassInfoType2 types/Test.C#ClassInfoType2#x(). => method x => Int types/Test.C#ClassInfoType3# => trait ClassInfoType3 [typeparam T ] extends Object { self: ClassInfoType3[T] => +2 decls } -types/Test.C#ClassInfoType3#[T] => typeparam T +types/Test.C#ClassInfoType3#[T] => typeparam T types/Test.C#ClassInfoType3#``(). => primary ctor [typeparam T ](): ClassInfoType3[T] types/Test.C#Either. => val method Either Either.type types/Test.C#MethodType. => final object MethodType extends Object { self: MethodType.type => +7 decls } @@ -5215,7 +5209,7 @@ types/Test.C#MethodType.m5(). => method m5 (param x: Int): Int types/Test.C#MethodType.m5().(x) => param x: Int types/Test.C#MethodType.m6(). => method m6 [typeparam T ](param x: T): T types/Test.C#MethodType.m6().(x) => param x: T -types/Test.C#MethodType.m6().[T] => typeparam T +types/Test.C#MethodType.m6().[T] => typeparam T types/Test.C#MethodType.x1(). => method x1 => Int types/Test.C#MethodType.x2(). => method x2 => Int types/Test.C#RepeatedType# => case class RepeatedType extends Object with Product with Serializable { self: RepeatedType => +4 decls } @@ -5232,15 +5226,15 @@ types/Test.C#RepeatedType.toString(). => method toString => String <: scala/Any# types/Test.C#RepeatedType.unapplySeq(). => method unapplySeq (param x$1: RepeatedType): RepeatedType types/Test.C#RepeatedType.unapplySeq().(x$1) => param x$1: RepeatedType types/Test.C#TypeType. => final object TypeType extends Object { self: TypeType.type => +6 decls } -types/Test.C#TypeType.T1# => type T1 +types/Test.C#TypeType.T1# => type T1 types/Test.C#TypeType.T4# => type T4 = C types/Test.C#TypeType.T5# => type T5 [typeparam U ] = U -types/Test.C#TypeType.T5#[U] => typeparam U +types/Test.C#TypeType.T5#[U] => typeparam U types/Test.C#TypeType.m2(). => method m2 [typeparam T2 = C]: Nothing types/Test.C#TypeType.m2().[T2] => typeparam T2 = C types/Test.C#TypeType.m3(). => method m3 [typeparam M3 [type _ ]]: Nothing types/Test.C#TypeType.m3().[M3] => typeparam M3 [type _ ] -types/Test.C#TypeType.m3().[M3][_] => type _ +types/Test.C#TypeType.m3().[M3][_] => type _ types/Test.C#``(). => primary ctor (): C types/Test.C#annType1. => val method annType1 T @ann[T] types/Test.C#annType2. => val method annType2 T @ann1 @ann2 @@ -5263,7 +5257,7 @@ types/Test.C#thisType1. => val method thisType1 C.this.type types/Test.C#thisType2. => val method thisType2 C.this.type types/Test.C#typeLambda1(). => method typeLambda1 [typeparam M [type _ ]]: Nothing types/Test.C#typeLambda1().[M] => typeparam M [type _ ] -types/Test.C#typeLambda1().[M][_] => type _ +types/Test.C#typeLambda1().[M][_] => type _ types/Test.C#typeRef1. => val method typeRef1 C types/Test.C#typeRef2. => val method typeRef2 p.C types/Test.C#typeRef3. => val method typeRef3 T#C @@ -5288,7 +5282,7 @@ types/Test.N# => trait N extends Object { self: N => +2 decls } types/Test.N#``(). => primary ctor (): N types/Test.N#n(). => method n => Int types/ann# => class ann [typeparam T ] extends Annotation with StaticAnnotation { self: ann[T] => +3 decls } -types/ann#[T] => typeparam T +types/ann#[T] => typeparam T types/ann#``(). => primary ctor [typeparam T ](param x: T): ann[T] types/ann#``().(x) => param x: T types/ann#x. => private[this] val method x T From 2834aae04bb38bc6f919b715f0a5787c476386c6 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Thu, 27 Feb 2025 12:56:44 -0800 Subject: [PATCH 191/505] Suppression toString [Cherry-picked 3e61bd9007ee852c0e26dcec5c517f76b1e5d2dc] --- compiler/src/dotty/tools/dotc/reporting/WConf.scala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/reporting/WConf.scala b/compiler/src/dotty/tools/dotc/reporting/WConf.scala index fd5c7cc0dbeb..95e9652c796c 100644 --- a/compiler/src/dotty/tools/dotc/reporting/WConf.scala +++ b/compiler/src/dotty/tools/dotc/reporting/WConf.scala @@ -139,8 +139,10 @@ object WConf: class Suppression(val annotPos: SourcePosition, filters: List[MessageFilter], val start: Int, val end: Int, val verbose: Boolean): private[this] var _used = false def used: Boolean = _used - def markUsed(): Unit = { _used = true } - + def markUsed(): Unit = + _used = true def matches(dia: Diagnostic): Boolean = val pos = dia.pos pos.exists && start <= pos.start && pos.end <= end && filters.forall(_.matches(dia)) + + override def toString = s"Suppress in ${annotPos.source} $start..$end [${filters.mkString(", ")}]" From 808818f9aa86046a2e9164cdf00f76576590c584 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Thu, 27 Feb 2025 09:04:11 -0800 Subject: [PATCH 192/505] Register nowarn when inlining --- compiler/src/dotty/tools/dotc/Run.scala | 28 +++++++++++++-- .../dotty/tools/dotc/inlines/Inliner.scala | 15 +++++++- .../dotty/tools/dotc/inlines/Inlines.scala | 6 ++++ .../src/dotty/tools/dotc/typer/Typer.scala | 34 +++++-------------- tests/warn/i22672/lib_1.scala | 15 ++++++++ tests/warn/i22672/usage_2.scala | 13 +++++++ 6 files changed, 82 insertions(+), 29 deletions(-) create mode 100644 tests/warn/i22672/lib_1.scala create mode 100644 tests/warn/i22672/usage_2.scala diff --git a/compiler/src/dotty/tools/dotc/Run.scala b/compiler/src/dotty/tools/dotc/Run.scala index 7dace14ac068..79b49653746b 100644 --- a/compiler/src/dotty/tools/dotc/Run.scala +++ b/compiler/src/dotty/tools/dotc/Run.scala @@ -17,15 +17,15 @@ import Phases.{unfusedPhases, Phase} import sbt.interfaces.ProgressCallback import util.* -import reporting.{Suppression, Action, Profile, ActiveProfile, NoProfile} -import reporting.Diagnostic -import reporting.Diagnostic.Warning +import reporting.{Suppression, Action, Profile, ActiveProfile, MessageFilter, NoProfile, WConf} +import reporting.Diagnostic, Diagnostic.Warning import rewrites.Rewrites import profile.Profiler import printing.XprintMode import typer.ImplicitRunInfo import config.Feature import StdNames.nme +import Spans.Span import java.io.{BufferedWriter, OutputStreamWriter} import java.nio.charset.StandardCharsets @@ -37,6 +37,8 @@ import scala.io.Codec import Run.Progress import scala.compiletime.uninitialized import dotty.tools.dotc.transform.MegaPhase +import dotty.tools.dotc.util.chaining.* +import java.util.{Timer, TimerTask} /** A compiler run. Exports various methods to compile source files */ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with ConstraintRunInfo { @@ -97,6 +99,26 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint Action.Warning } + def registerNowarn(annotPos: SourcePosition, range: Span)(conf: String, pos: SrcPos)(using Context): Unit = + var verbose = false + val filters = conf match + case "" => + List(MessageFilter.Any) + case "none" => + List(MessageFilter.None) + case "verbose" | "v" => + verbose = true + List(MessageFilter.Any) + case conf => + WConf.parseFilters(conf).left.map: parseErrors => + report.warning(s"Invalid message filter\n${parseErrors.mkString("\n")}", pos) + List(MessageFilter.None) + .merge + addSuppression: + Suppression(annotPos, filters, range.start, range.end, verbose) + .tap: sup => + if filters == List(MessageFilter.None) then sup.markUsed() // invalid suppressions, don't report as unused + def addSuppression(sup: Suppression): Unit = val suppressions = mySuppressions.getOrElseUpdate(sup.annotPos.source, ListBuffer.empty) if sup.start != sup.end && suppressions.forall(x => x.start != sup.start || x.end != sup.end) then diff --git a/compiler/src/dotty/tools/dotc/inlines/Inliner.scala b/compiler/src/dotty/tools/dotc/inlines/Inliner.scala index 4404ae9f9ea4..686f49aa9248 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inliner.scala @@ -98,7 +98,8 @@ object Inliner: // InlinerMap is a TreeTypeMap with special treatment for inlined arguments: // They are generally left alone (not mapped further, and if they wrap a type - // the type Inlined wrapper gets dropped + // the type Inlined wrapper gets dropped. + // As a side effect, register @nowarn annotations from annotated expressions. private class InlinerMap( typeMap: Type => Type, treeMap: Tree => Tree, @@ -115,6 +116,18 @@ object Inliner: ConservativeTreeCopier() ): + override def transform(tree: Tree)(using Context): Tree = + tree match + case Typed(expr, tpt) => + tpt.tpe match + case AnnotatedType(_, annot) if annot.hasSymbol(defn.NowarnAnnot) => + val argPos = annot.argument(0).getOrElse(tree).sourcePos + val conf = annot.argumentConstantString(0).getOrElse("") + ctx.run.nn.suppressions.registerNowarn(tree.sourcePos, expr.span)(conf, argPos) + case _ => + case _ => + super.transform(tree) + override def copy( typeMap: Type => Type, treeMap: Tree => Tree, diff --git a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala index e9ac2b92a488..598c3c91ea2f 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala @@ -23,6 +23,7 @@ import collection.mutable import reporting.{NotConstant, trace} import util.Spans.Span import dotty.tools.dotc.core.Periods.PhaseId +import dotty.tools.dotc.util.chaining.* /** Support for querying inlineable methods and for inlining calls to such methods */ object Inlines: @@ -44,6 +45,11 @@ object Inlines: def bodyToInline(sym: SymDenotation)(using Context): Tree = if hasBodyToInline(sym) then sym.getAnnotation(defn.BodyAnnot).get.tree + .tap: body => + for annot <- sym.getAnnotation(defn.NowarnAnnot) do + val argPos = annot.argument(0).getOrElse(annot.tree).sourcePos + val conf = annot.argumentConstantString(0).getOrElse("") + ctx.run.nn.suppressions.registerNowarn(annot.tree.sourcePos, body.span)(conf, argPos) else EmptyTree diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 42a0c24c9f24..bdf1151e9b35 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -2486,31 +2486,15 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer def registerNowarn(tree: Tree, mdef: untpd.Tree)(using Context): Unit = val annot = Annotations.Annotation(tree) - def argPos = annot.argument(0).getOrElse(tree).sourcePos - var verbose = false - val filters = annot.argumentConstantString(0) match - case None => annot.argument(0) match - case Some(t: Select) if t.name.is(DefaultGetterName) => - // default argument used for `@nowarn` and `@nowarn()` - List(MessageFilter.Any) - case _ => - report.warning(s"filter needs to be a compile-time constant string", argPos) - List(MessageFilter.None) - case Some("") => - List(MessageFilter.Any) - case Some("verbose") | Some("v") => - verbose = true - List(MessageFilter.Any) - case Some(s) => - WConf.parseFilters(s).left.map(parseErrors => - report.warning (s"Invalid message filter\n${parseErrors.mkString ("\n")}", argPos) - List(MessageFilter.None) - ).merge - val range = mdef.sourcePos - val sup = Suppression(tree.sourcePos, filters, range.start, range.end, verbose) - // invalid suppressions, don't report as unused - if filters == List(MessageFilter.None) then sup.markUsed() - ctx.run.nn.suppressions.addSuppression(sup) + val argPos = annot.argument(0).getOrElse(tree).sourcePos + val conf = annot.argumentConstantString(0).getOrElse: + annot.argument(0) match + case Some(t: Select) if t.name.is(DefaultGetterName) => + "" // default argument used for `@nowarn` and `@nowarn()` + case _ => + report.warning(s"filter needs to be a compile-time constant string", argPos) + "none" // not a -Wconf filter, mapped to MessageFilter.None by registerNowarn + ctx.run.nn.suppressions.registerNowarn(tree.sourcePos, mdef.span)(conf, argPos) def typedValDef(vdef: untpd.ValDef, sym: Symbol)(using Context): Tree = ctx.profiler.onTypedDef(sym) { val ValDef(name, tpt, _) = vdef diff --git a/tests/warn/i22672/lib_1.scala b/tests/warn/i22672/lib_1.scala new file mode 100644 index 000000000000..19e36e61a556 --- /dev/null +++ b/tests/warn/i22672/lib_1.scala @@ -0,0 +1,15 @@ + +package p + +import annotation.* + +@deprecated("old api", since="1.0") +def g = 42 + +//@deprecated("new api", since="1.0") +@nowarn("cat=deprecation") +inline def f = + g + +transparent inline def body = + g: @nowarn diff --git a/tests/warn/i22672/usage_2.scala b/tests/warn/i22672/usage_2.scala new file mode 100644 index 000000000000..39c0550b8fd4 --- /dev/null +++ b/tests/warn/i22672/usage_2.scala @@ -0,0 +1,13 @@ + +//> using options -deprecation + +package q + +def test = p.f // inline f is nowarn + +def bodily = p.body // transparent inline with annotated body + +@deprecated("do I even know how it works", since="0.1") +def huh = "hello" + +def failing = huh // warn From 5abed37491aa7b39bee9b83a2373ec8543f19314 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Sat, 26 Apr 2025 10:58:03 +0200 Subject: [PATCH 193/505] Register nowarn when inlining [Cherry-picked 3c18222f1bf2040e8d07626be3a39bcd60bbfa49][modified] From 8f7101fb9795d1c5daea046707421dcc25c8d43a Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Mon, 10 Mar 2025 11:41:13 -0700 Subject: [PATCH 194/505] Handle multiple annotations [Cherry-picked daf88c77b8272b11b9206993fd18db1dcc5a5843] --- .../src/dotty/tools/dotc/inlines/Inliner.scala | 17 +++++++++++------ tests/warn/i22672/lib_1.scala | 5 +++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/inlines/Inliner.scala b/compiler/src/dotty/tools/dotc/inlines/Inliner.scala index 686f49aa9248..50eaa0f57e38 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inliner.scala @@ -119,12 +119,17 @@ object Inliner: override def transform(tree: Tree)(using Context): Tree = tree match case Typed(expr, tpt) => - tpt.tpe match - case AnnotatedType(_, annot) if annot.hasSymbol(defn.NowarnAnnot) => - val argPos = annot.argument(0).getOrElse(tree).sourcePos - val conf = annot.argumentConstantString(0).getOrElse("") - ctx.run.nn.suppressions.registerNowarn(tree.sourcePos, expr.span)(conf, argPos) - case _ => + def loop(tpe: Type): Unit = + tpe match + case AnnotatedType(parent, annot) => + if annot.hasSymbol(defn.NowarnAnnot) then + val argPos = annot.argument(0).getOrElse(tree).sourcePos + val conf = annot.argumentConstantString(0).getOrElse("") + ctx.run.nn.suppressions.registerNowarn(tree.sourcePos, expr.span)(conf, argPos) + else + loop(parent) + case _ => + loop(tpt.tpe) case _ => super.transform(tree) diff --git a/tests/warn/i22672/lib_1.scala b/tests/warn/i22672/lib_1.scala index 19e36e61a556..722f2ae03899 100644 --- a/tests/warn/i22672/lib_1.scala +++ b/tests/warn/i22672/lib_1.scala @@ -1,7 +1,7 @@ package p -import annotation.* +import annotation.{unchecked as _, *} @deprecated("old api", since="1.0") def g = 42 @@ -12,4 +12,5 @@ inline def f = g transparent inline def body = - g: @nowarn + g: @nowarn @unchecked + g: @unchecked @nowarn From be7c9bbdbf26cec20c389f8f1849ec98f0a20839 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Mon, 10 Mar 2025 15:18:22 -0700 Subject: [PATCH 195/505] Collect nowarn symbols instead of skipping them [Cherry-picked d0a11e021d65ce6801fe9f86365f25f4cd1a0e59] --- .../src/dotty/tools/dotc/transform/CheckUnused.scala | 11 ++++++++--- tests/warn/i15503d.scala | 2 +- tests/warn/t13095.scala | 10 ++++++++++ 3 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 tests/warn/t13095.scala diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index 005ce5ba3f64..4d071618ac71 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -441,6 +441,7 @@ object CheckUnused: val refs = mutable.Set.empty[Symbol] // references val asss = mutable.Set.empty[Symbol] // targets of assignment val skip = mutable.Set.empty[Symbol] // methods to skip (don't warn about their params) + val nowarn = mutable.Set.empty[Symbol] // marked @nowarn val imps = new IdentityHashMap[Import, Unit] // imports val sels = new IdentityHashMap[ImportSelector, Unit] // matched selectors def register(tree: Tree)(using Context): Unit = if inlined.isEmpty then @@ -453,7 +454,9 @@ object CheckUnused: then imps.put(imp, ()) case tree: Bind => - if !tree.name.isInstanceOf[DerivedName] && !tree.name.is(WildcardParamName) && !tree.hasAttachment(NoWarn) then + if !tree.name.isInstanceOf[DerivedName] && !tree.name.is(WildcardParamName) then + if tree.hasAttachment(NoWarn) then + nowarn.addOne(tree.symbol) pats.addOne((tree.symbol, tree.namePos)) case tree: NamedDefTree => if tree.hasAttachment(PatternVar) then @@ -461,9 +464,10 @@ object CheckUnused: pats.addOne((tree.symbol, tree.namePos)) else if (tree.symbol ne NoSymbol) && !tree.name.isWildcard - && !tree.hasAttachment(NoWarn) && !tree.symbol.is(ModuleVal) // track only the ModuleClass using the object symbol, with correct namePos then + if tree.hasAttachment(NoWarn) then + nowarn.addOne(tree.symbol) defs.addOne((tree.symbol.userSymbol, tree.namePos)) case _ => if tree.symbol ne NoSymbol then @@ -531,6 +535,7 @@ object CheckUnused: && !sym.name.is(BodyRetainerName) && !sym.isSerializationSupport && !(sym.is(Mutable) && sym.isSetter && sym.owner.is(Trait)) // tracks sym.underlyingSymbol sibling getter + && !infos.nowarn(sym) then warnAt(pos)(UnusedSymbol.privateMembers) @@ -627,7 +632,7 @@ object CheckUnused: val byPos = infos.pats.groupMap(uniformPos(_, _))((sym, pos) => sym) for (pos, syms) <- byPos if pos.span.exists && !syms.exists(_.hasAnnotation(defn.UnusedAnnot)) do if !syms.exists(infos.refs(_)) then - if !syms.exists(v => !v.isLocal && !v.is(Private)) then + if !syms.exists(v => !v.isLocal && !v.is(Private) || infos.nowarn(v)) then warnAt(pos)(UnusedSymbol.patVars) else if syms.exists(_.is(Mutable)) then // check unassigned var val sym = // recover the original diff --git a/tests/warn/i15503d.scala b/tests/warn/i15503d.scala index 1e1adca51b46..073b340637fa 100644 --- a/tests/warn/i15503d.scala +++ b/tests/warn/i15503d.scala @@ -22,7 +22,7 @@ case class K(i: Int, j: Int) class C(c0: Option[Int], k0: K): private val Some(c) = c0: @unchecked // warn valdef from pattern - private val K(i, j) = k0 // warn // warn valdefs from pattern (RHS patvars are NoWarn) + private val K(i, j) = k0 // nowarn (name of case class element is nowarn) val K(v, w) = k0 // nowarn nonprivate private val K(r, s) = k0 // warn // warn valdefs from pattern def f(x: Option[Int]) = x match diff --git a/tests/warn/t13095.scala b/tests/warn/t13095.scala new file mode 100644 index 000000000000..0634f4ed903d --- /dev/null +++ b/tests/warn/t13095.scala @@ -0,0 +1,10 @@ +//> using options -Wunused:patvars -Werror + +case class A(x: Int, y: Int) + +object Main { + for { + a <- List.empty[A] + A(x, y) = a + } yield x + y +} From 19a0db602f259b8762f96baf6639a3cafdf697cf Mon Sep 17 00:00:00 2001 From: Daniel Thoma Date: Thu, 20 Feb 2025 22:30:18 +0100 Subject: [PATCH 196/505] Fixes #15736 Box native instantiated method return type if sam method return type is not a primitive type to satisfy conditions specified in https://docs.oracle.com/javase/8/docs/api/java/lang/invoke/LambdaMetafactory.html Condition is not enforced by JVM but by Android ART. [Cherry-picked 24d8ecbf6d498d58e35e53910bf2ec6de8d0e060] --- .../tools/backend/jvm/BCodeBodyBuilder.scala | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala b/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala index 9c270482c6d4..836f5040b26e 100644 --- a/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala +++ b/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala @@ -1773,8 +1773,6 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder { val returnUnit = lambdaTarget.info.resultType.typeSymbol == defn.UnitClass val functionalInterfaceDesc: String = generatedType.descriptor val desc = capturedParamsTypes.map(tpe => toTypeKind(tpe)).mkString(("("), "", ")") + functionalInterfaceDesc - // TODO specialization - val instantiatedMethodType = new MethodBType(lambdaParamTypes.map(p => toTypeKind(p)), toTypeKind(lambdaTarget.info.resultType)).toASMType val samMethod = atPhase(erasurePhase) { val samMethods = toDenot(functionalInterface).info.possibleSamMethods.toList @@ -1787,7 +1785,21 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder { } val methodName = samMethod.javaSimpleName - val samMethodType = asmMethodType(samMethod).toASMType + val samMethodBType = asmMethodType(samMethod) + val samMethodType = samMethodBType.toASMType + + def boxInstantiated(instantiatedType: BType, samType: BType): BType = + if(!samType.isPrimitive && instantiatedType.isPrimitive) + boxedClassOfPrimitive(instantiatedType.asPrimitiveBType) + else instantiatedType + // TODO specialization + val instantiatedMethodBType = new MethodBType( + lambdaParamTypes.map(p => toTypeKind(p)), + boxInstantiated(toTypeKind(lambdaTarget.info.resultType), samMethodBType.returnType) + ) + + val instantiatedMethodType = instantiatedMethodBType.toASMType + // scala/bug#10334: make sure that a lambda object for `T => U` has a method `apply(T)U`, not only the `(Object)Object` // version. Using the lambda a structural type `{def apply(t: T): U}` causes a reflective lookup for this method. val needsGenericBridge = samMethodType != instantiatedMethodType From af0e3add1c852a075a6ddbaa4ce9e254573392dd Mon Sep 17 00:00:00 2001 From: rochala Date: Wed, 27 Sep 2023 12:26:20 +0200 Subject: [PATCH 197/505] Add enum type param support in sourceSymbol [Cherry-picked 62e3af5feb89e5ee7a0047f1cf0d4cda61ccb409] --- .../src/dotty/tools/dotc/core/Symbols.scala | 16 +++++++-- .../tools/dotc/interactive/Interactive.scala | 1 + .../tools/languageserver/DefinitionTest.scala | 34 +++++++++++++++++++ .../tests/definition/PcDefinitionSuite.scala | 27 +++++++++++++++ 4 files changed, 76 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 893392794a51..e2cc098398e9 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -323,13 +323,25 @@ object Symbols extends SymUtils { targets.match case (tp: NamedType) :: _ => tp.symbol.sourceSymbol case _ => this - else if (denot.is(Synthetic)) { + else if denot.is(Synthetic) then val linked = denot.linkedClass if (linked.exists && !linked.is(Synthetic)) linked else denot.owner.sourceSymbol - } + else if ( + denot.is(TypeParam) && + denot.maybeOwner.maybeOwner.isAllOf(EnumCase) && + denot.maybeOwner.isPrimaryConstructor + ) then + val enclosingEnumCase = denot.maybeOwner.maybeOwner + val caseTypeParam = enclosingEnumCase.typeParams.find(_.name == denot.name) + if caseTypeParam.exists(_.is(Synthetic)) then + val enumClass = enclosingEnumCase.info.firstParent.typeSymbol + val sourceTypeParam = enumClass.typeParams.find(_.name == denot.name) + sourceTypeParam.getOrElse(this) + else + caseTypeParam.getOrElse(this) else if (denot.isPrimaryConstructor) denot.owner.sourceSymbol else this diff --git a/compiler/src/dotty/tools/dotc/interactive/Interactive.scala b/compiler/src/dotty/tools/dotc/interactive/Interactive.scala index a03ae502f2f1..f1db0c949cef 100644 --- a/compiler/src/dotty/tools/dotc/interactive/Interactive.scala +++ b/compiler/src/dotty/tools/dotc/interactive/Interactive.scala @@ -144,6 +144,7 @@ object Interactive { ( sym == tree.symbol || sym.exists && sym == tree.symbol.sourceSymbol + || sym.exists && sym.sourceSymbol == tree.symbol || !include.isEmpty && sym.name == tree.symbol.name && sym.maybeOwner != tree.symbol.maybeOwner && ( include.isOverridden && overrides(sym, tree.symbol) || include.isOverriding && overrides(tree.symbol, sym) diff --git a/language-server/test/dotty/tools/languageserver/DefinitionTest.scala b/language-server/test/dotty/tools/languageserver/DefinitionTest.scala index ddacd0c868e0..d6de3d971e2b 100644 --- a/language-server/test/dotty/tools/languageserver/DefinitionTest.scala +++ b/language-server/test/dotty/tools/languageserver/DefinitionTest.scala @@ -378,4 +378,38 @@ class DefinitionTest { .definition(m3 to m4, Nil) .definition(m5 to m6, Nil) .definition(m7 to m8, Nil) + + @Test def typeParam: Unit = { + code"""|class Foo[${m1}T${m2}]: + | def test: ${m3}T${m4}""" + .definition(m3 to m4, List(m1 to m2)) + } + + @Test def enumTypeParam: Unit = { + code"""|enum Test[${m1}T${m2}]: + | case EnumCase(value: ${m3}T${m4})""" + .definition(m3 to m4, List(m1 to m2)) + } + + @Test def extMethodTypeParam: Unit = { + code"""extension [${m1}T${m2}](string: String) def xxxx(y: ${m3}T${m4}) = ???""" + .definition(m3 to m4, List(m1 to m2)) + } + + @Test def typeParamCovariant: Unit = { + code"""|class Foo[+${m1}T${m2}]: + | def test: ${m3}T${m4}""" + .definition(m3 to m4, List(m1 to m2)) + } + + @Test def enumTypeParamCovariant: Unit = { + code"""|enum Test[+${m1}T${m2}]: + | case EnumCase(value: ${m3}T${m4})""" + .definition(m3 to m4, List(m1 to m2)) + } + + @Test def extMethodTypeParamCovariant: Unit = { + code"""extension [+${m1}T${m2}](string: String) def xxxx(y: ${m3}T${m4}) = ???""" + .definition(m3 to m4, List(m1 to m2)) + } } diff --git a/presentation-compiler/test/dotty/tools/pc/tests/definition/PcDefinitionSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/definition/PcDefinitionSuite.scala index fab21ffdee0a..2075cdfb03fe 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/definition/PcDefinitionSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/definition/PcDefinitionSuite.scala @@ -478,6 +478,33 @@ class PcDefinitionSuite extends BasePcDefinitionSuite: |""".stripMargin ) + @Test def `enum-class-type-param` = + check( + """| + |enum Options[<>]: + | case Some(x: A@@A) + | case None extends Options[Nothing] + |""".stripMargin + ) + + @Test def `enum-class-type-param-covariant` = + check( + """| + |enum Options[+<>]: + | case Some(x: A@@A) + | case None extends Options[Nothing] + |""".stripMargin + ) + + @Test def `enum-class-type-param-duplicate` = + check( + """| + |enum Testing[AA]: + | case Some[<>](x: A@@A) extends Testing[AA] + | case None extends Testing[Nothing] + |""".stripMargin + ) + @Test def `derives-def` = check( """| From 9c0b91d24b8602743147a04995d2e3a57d7b84c0 Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Fri, 14 Mar 2025 07:44:50 +0100 Subject: [PATCH 198/505] Add support for running the `test` sub-command with the bisect script (#22796) Example usage: ```bash scala project/scripts/bisect.scala --jvm 17 -- --bootstrapped --releases 3.6.4-RC1-bin-20241120-bd07317-NIGHTLY... test smth.test.scala ``` `smth.test.scala` ```scala //> using dep org.scalameta::munit::1.1.0 //> using platform js class MyTests extends munit.FunSuite { test("foo") { assert(2 + 2 == 4) } } ``` Allowed to bisect https://github.com/scala/scala3/issues/22794 [Cherry-picked c9eaa14115c2654db4f54294b0571bc28a6051a4] --- project/scripts/bisect.scala | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/project/scripts/bisect.scala b/project/scripts/bisect.scala index d920dfd528a1..fb53807f62b6 100755 --- a/project/scripts/bisect.scala +++ b/project/scripts/bisect.scala @@ -20,6 +20,7 @@ val usageMessage = """ |The should be one of: |* compile ... |* run ... + |* test ... |* | |The arguments for 'compile' and 'run' should be paths to the source file(s) and optionally additional options passed directly to scala-cli. @@ -100,6 +101,7 @@ object ScriptOptions: enum ValidationCommand: case Compile(args: Seq[String]) case Run(args: Seq[String]) + case Test(args: Seq[String]) case CustomValidationScript(scriptFile: File) def validationScript: File = this match @@ -107,6 +109,8 @@ enum ValidationCommand: ValidationScript.tmpScalaCliScript(command = "compile", args) case Run(args) => ValidationScript.tmpScalaCliScript(command = "run", args) + case Test(args) => + ValidationScript.tmpScalaCliScript(command = "test", args) case CustomValidationScript(scriptFile) => ValidationScript.copiedFrom(scriptFile) @@ -114,6 +118,7 @@ object ValidationCommand: def fromArgs(args: Seq[String]) = args match case Seq("compile", commandArgs*) => Compile(commandArgs) case Seq("run", commandArgs*) => Run(commandArgs) + case Seq("test", commandArgs*) => Test(commandArgs) case Seq(path) => CustomValidationScript(new File(path)) From 96e3684ef36e017efc1f9ed9f3bb16cde202696d Mon Sep 17 00:00:00 2001 From: kasiaMarek Date: Tue, 11 Mar 2025 15:44:06 +0100 Subject: [PATCH 199/505] fix: go to def should lead to all: apply, object and class --- .../dotty/tools/pc/MetalsInteractive.scala | 13 ++- .../dotty/tools/pc/PcDefinitionProvider.scala | 80 ++++++++----------- .../tests/definition/PcDefinitionSuite.scala | 72 +++++++++++++++++ 3 files changed, 118 insertions(+), 47 deletions(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/MetalsInteractive.scala b/presentation-compiler/src/main/dotty/tools/pc/MetalsInteractive.scala index dc4fa0446715..f5de56711118 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/MetalsInteractive.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/MetalsInteractive.scala @@ -100,9 +100,9 @@ object MetalsInteractive: pos: SourcePosition, indexed: IndexedContext, skipCheckOnName: Boolean = false - ): List[Symbol] = + )(using Context): List[Symbol] = enclosingSymbolsWithExpressionType(path, pos, indexed, skipCheckOnName) - .map(_._1) + .map(_._1.sourceSymbol) /** * Returns the list of tuple enclosing symbol and @@ -203,6 +203,15 @@ object MetalsInteractive: case _ => Nil + case head :: (sel @ Select(_, name)) :: _ + if head.sourcePos.encloses(sel.sourcePos) && (name == StdNames.nme.apply || name == StdNames.nme.unapply) => + val optObjectSymbol = List(head.symbol).filter(sym => !(sym.is(Synthetic) && sym.is(Module))) + val classSymbol = head.symbol.companionClass + val optApplySymbol = List(sel.symbol).filter(sym => !sym.is(Synthetic)) + val symbols = optObjectSymbol ++ (classSymbol :: optApplySymbol) + symbols.collect: + case sym if sym.exists => (sym, sym.info, None) + case path @ head :: tail => if head.symbol.is(Exported) then val sym = head.symbol.sourceSymbol diff --git a/presentation-compiler/src/main/dotty/tools/pc/PcDefinitionProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/PcDefinitionProvider.scala index 8ff43ba07358..9fbaa8dcd16d 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/PcDefinitionProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/PcDefinitionProvider.scala @@ -79,7 +79,7 @@ class PcDefinitionProvider( .untypedPath(pos.span) .collect { case t: untpd.Tree => t } - definitionsForSymbol(untpdPath.headOption.map(_.symbol).toList, uri, pos) + definitionsForSymbols(untpdPath.headOption.map(_.symbol).toList, uri, pos) end fallbackToUntyped private def findDefinitions( @@ -89,7 +89,7 @@ class PcDefinitionProvider( uri: URI, ): DefinitionResult = import indexed.ctx - definitionsForSymbol( + definitionsForSymbols( MetalsInteractive.enclosingSymbols(path, pos, indexed), uri, pos @@ -113,68 +113,58 @@ class PcDefinitionProvider( case Nil => path.headOption match case Some(value: Literal) => - definitionsForSymbol(List(value.typeOpt.widen.typeSymbol), uri, pos) + definitionsForSymbols(List(value.typeOpt.widen.typeSymbol), uri, pos) case _ => DefinitionResultImpl.empty case _ => - definitionsForSymbol(typeSymbols, uri, pos) - + definitionsForSymbols(typeSymbols, uri, pos) end findTypeDefinitions - private def definitionsForSymbol( + private def definitionsForSymbols( symbols: List[Symbol], uri: URI, pos: SourcePosition )(using ctx: Context): DefinitionResult = - symbols match - case symbols @ (sym :: other) => - val isLocal = sym.source == pos.source - if isLocal then - val include = Include.definitions | Include.local - val (exportedDefs, otherDefs) = - Interactive.findTreesMatching(driver.openedTrees(uri), include, sym) - .partition(_.tree.symbol.is(Exported)) - - otherDefs.headOption.orElse(exportedDefs.headOption) match - case Some(srcTree) => - val pos = srcTree.namePos - if pos.exists then - val loc = new Location(params.uri().toString(), pos.toLsp) - DefinitionResultImpl( - SemanticdbSymbols.symbolName(sym), - List(loc).asJava, - ) - else DefinitionResultImpl.empty - case None => - DefinitionResultImpl.empty - else - val res = new ArrayList[Location]() - semanticSymbolsSorted(symbols) - .foreach { sym => - res.addAll(search.definition(sym, params.uri())) - } - DefinitionResultImpl( - SemanticdbSymbols.symbolName(sym), - res - ) - end if + semanticSymbolsSorted(symbols) match case Nil => DefinitionResultImpl.empty - end match - end definitionsForSymbol + case syms @ ((_, headSym) :: tail) => + val locations = syms.flatMap: + case (sym, semanticdbSymbol) => + locationsForSymbol(sym, semanticdbSymbol, uri, pos) + DefinitionResultImpl(headSym, locations.asJava) + + private def locationsForSymbol( + symbol: Symbol, + semanticdbSymbol: String, + uri: URI, + pos: SourcePosition + )(using ctx: Context): List[Location] = + val isLocal = symbol.source == pos.source + if isLocal then + val trees = driver.openedTrees(uri) + val include = Include.definitions | Include.local + val (exportedDefs, otherDefs) = + Interactive.findTreesMatching(trees, include, symbol) + .partition(_.tree.symbol.is(Exported)) + otherDefs.headOption.orElse(exportedDefs.headOption).collect: + case srcTree if srcTree.namePos.exists => + new Location(params.uri().toString(), srcTree.namePos.toLsp) + .toList + else search.definition(semanticdbSymbol, uri).asScala.toList def semanticSymbolsSorted( syms: List[Symbol] - )(using ctx: Context): List[String] = + )(using ctx: Context): List[(Symbol, String)] = syms - .map { sym => + .collect { case sym if sym.exists => // in case of having the same type and teerm symbol // term comes first // used only for ordering symbols that come from `Import` val termFlag = if sym.is(ModuleClass) then sym.sourceModule.isTerm else sym.isTerm - (termFlag, SemanticdbSymbols.symbolName(sym)) + (termFlag, sym.sourceSymbol, SemanticdbSymbols.symbolName(sym)) } - .sorted - .map(_._2) + .sortBy { case (termFlag, _, name) => (termFlag, name) } + .map(_.tail) end PcDefinitionProvider diff --git a/presentation-compiler/test/dotty/tools/pc/tests/definition/PcDefinitionSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/definition/PcDefinitionSuite.scala index 2075cdfb03fe..a3f09b97d3f8 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/definition/PcDefinitionSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/definition/PcDefinitionSuite.scala @@ -531,3 +531,75 @@ class PcDefinitionSuite extends BasePcDefinitionSuite: |val a = MyIntOut(1).un@@even |""".stripMargin, ) + + @Test def `object` = + check( + """|package a + |object <> { + | def foo = 42 + |} + |val m = B@@ar.foo + |""".stripMargin + ) + + @Test def i7267 = + check( + """|package a + |trait Foo { + | def someNum: Int + | def <>(i: Int): Unit = println(someNum) + |} + |object <> extends Foo { + | def someNum = 42 + |} + | + |object Test { + | B@@ar(2) + |} + |""".stripMargin + ) + + @Test def `i7267-2` = + check( + """|package b + |trait Foo { + | def someNum: Int + | def <>(i: Int): Option[Int] = Some(i) + |} + |object <> extends Foo { + | def someNum = 42 + |} + | + |object Test { + | Bar.someNum match { + | case B@@ar(1) => ??? + | case _ => + | } + |} + |""".stripMargin + ) + + @Test def `i7267-3` = + check( + """|package c + |case class <>() + |object <> + |object O { + | val a = B@@ar() + |} + |""".stripMargin + ) + + @Test def `i7267-4` = + check( + """|package d + |class <>() + |object <> { + | def <>(): Bar = new Bar() + |} + |object O { + | val a = B@@ar() + |} + |""".stripMargin + ) + From 3c90b9109d7f2891e04b796d71d90b25696764d6 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Sat, 26 Apr 2025 10:59:51 +0200 Subject: [PATCH 200/505] fix: go to def should lead to all: apply, object and class [Cherry-picked 6785da26a167126e207e3da6f835b94780522e71][modified] From 3a8f0f983b5be60373ebb711090b9d0af26bac83 Mon Sep 17 00:00:00 2001 From: Hamza Remmal Date: Fri, 14 Mar 2025 01:49:45 +0100 Subject: [PATCH 201/505] chore: add support for 'abstract override' modifier [Cherry-picked b941fc1e286a0eff8018f067f0136ee675805e75] --- scaladoc/src/dotty/tools/scaladoc/api.scala | 1 + scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/api.scala b/scaladoc/src/dotty/tools/scaladoc/api.scala index 8ff40644fac2..878de14b3393 100644 --- a/scaladoc/src/dotty/tools/scaladoc/api.scala +++ b/scaladoc/src/dotty/tools/scaladoc/api.scala @@ -43,6 +43,7 @@ enum Modifier(val name: String, val prefix: Boolean): case Open extends Modifier("open", true) case Transparent extends Modifier("transparent", true) case Infix extends Modifier("infix", true) + case AbsOverride extends Modifier("abstract override", true) case class ExtensionTarget(name: String, typeParams: Seq[TypeParameter], argsLists: Seq[TermParameterList], signature: Signature, dri: DRI, position: Long) case class ImplicitConversion(from: DRI, to: DRI) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala index 5bc1b98a7fff..969b1d6462c2 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala @@ -98,7 +98,8 @@ object SymOps: Flags.Open -> Modifier.Open, Flags.Override -> Modifier.Override, Flags.Case -> Modifier.Case, - Flags.Opaque -> Modifier.Opaque + Flags.Opaque -> Modifier.Opaque, + Flags.AbsOverride -> Modifier.AbsOverride, ).collect { case (flag, mod) if sym.flags.is(flag) => mod } From d1877e41f9cffa3aad9eee90ca48f548a4a22e42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Fornal?= <24961583+Florian3k@users.noreply.github.com> Date: Sat, 15 Mar 2025 17:45:13 +0100 Subject: [PATCH 202/505] Scaladoc: fix generation of unique header ids (#22779) This PR fixes the generation of unique header id's. Previously, the id's were deduplicated globally, now they are deduplicated only within one page. Custom logic for that was removed, we now rely on `HeaderIdGenerator` from flexmark. [Cherry-picked 8734fbd664c8f91a3845925fa27c5a87cb8d98b1] --- .../markdown/SectionRenderingExtension.scala | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SectionRenderingExtension.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SectionRenderingExtension.scala index f2b2546c11ad..072591ea57bc 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SectionRenderingExtension.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SectionRenderingExtension.scala @@ -26,21 +26,17 @@ object SectionRenderingExtension extends HtmlRenderer.HtmlRendererExtension: def rendererOptions(opt: MutableDataHolder): Unit = () case class AnchorLink(link: String) extends BlankLine(BasedSequence.EmptyBasedSequence()) - object SectionHandler extends CustomNodeRenderer[Section]: - val repeatedIds: mutable.Map[(NodeRendererContext, String), Int] = mutable.Map() + class SectionHandler extends CustomNodeRenderer[Section]: val idGenerator = new HeaderIdGenerator.Factory().create() + idGenerator.setResolveDupes(true) override def render(node: Section, c: NodeRendererContext, html: HtmlWriter): Unit = val Section(header, body) = node - val headerText = header.getText.toString - val idSuffix = repeatedIds.getOrElseUpdate((c, headerText), 0) - val ifSuffixStr = if(idSuffix == 0) then "" else idSuffix.toString - repeatedIds.update((c, headerText), idSuffix + 1) /* #19524 flexmark's `HeaderIdGenerator` does not appear to be thread-safe, * so we protect its usage with a full `synchronize`. */ val id = idGenerator.synchronized { - idGenerator.getId(headerText + ifSuffixStr) + idGenerator.getId(header.getText) } val anchor = AnchorLink(s"#$id") @@ -68,13 +64,12 @@ object SectionRenderingExtension extends HtmlRenderer.HtmlRendererExtension: object Render extends NodeRenderer: override def getNodeRenderingHandlers: JSet[NodeRenderingHandler[_]] = JSet( - new NodeRenderingHandler(classOf[Section], SectionHandler), + new NodeRenderingHandler(classOf[Section], new SectionHandler), new NodeRenderingHandler(classOf[AnchorLink], AnchorLinkHandler) ) object Factory extends NodeRendererFactory: override def apply(options: DataHolder): NodeRenderer = Render - def extend(htmlRendererBuilder: HtmlRenderer.Builder, tpe: String): Unit = htmlRendererBuilder.nodeRendererFactory(Factory) From e7f088e4891b9a06d376d8d2e2af4017abc35632 Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Thu, 13 Mar 2025 12:39:46 +0100 Subject: [PATCH 203/505] Move type-projection file This commit only exists to avoid git being confused, it is not independent of the following commit ! --- .../{dropped-features => changed-features}/type-projection.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename docs/_docs/reference/{dropped-features => changed-features}/type-projection.md (92%) diff --git a/docs/_docs/reference/dropped-features/type-projection.md b/docs/_docs/reference/changed-features/type-projection.md similarity index 92% rename from docs/_docs/reference/dropped-features/type-projection.md rename to docs/_docs/reference/changed-features/type-projection.md index 08b5ffb34eca..2c3e82ce99b8 100644 --- a/docs/_docs/reference/dropped-features/type-projection.md +++ b/docs/_docs/reference/changed-features/type-projection.md @@ -9,7 +9,7 @@ and `A` names a type member of `T`. Scala 3 disallows this if `T` is an abstract type (class types and type aliases are fine). This change was made because unrestricted type projection -is [unsound](https://github.com/lampepfl/dotty/issues/1050). +is [unsound](https://github.com/scala/scala3/issues/1050). This restriction rules out the [type-level encoding of a combinator calculus](https://michid.wordpress.com/2010/01/29/scala-type-level-encoding-of-the-ski-calculus/). From c18c223c9684e027218285bfc0d1022401081e34 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Sat, 26 Apr 2025 11:00:40 +0200 Subject: [PATCH 204/505] Move type-projection file This commit only exists to avoid git being confused, it is not independent of the following commit ! [Cherry-picked 3d1d012c2191f24e77290aebae587deaa3fdf91d][modified] From 0ef884eefec2c05465818396b9455a48e7868d07 Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Thu, 13 Mar 2025 13:03:20 +0100 Subject: [PATCH 205/505] Reword reference article about type projection so that it highlights what is allowed Was previously focused on what was forbidden/dangerous which made it feel like an unsafe feature [Cherry-picked bb1a94634074a7c1d8a2704ea353fc946b50d58c] --- .../changed-features/type-projection.md | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/docs/_docs/reference/changed-features/type-projection.md b/docs/_docs/reference/changed-features/type-projection.md index 2c3e82ce99b8..32c56029ce51 100644 --- a/docs/_docs/reference/changed-features/type-projection.md +++ b/docs/_docs/reference/changed-features/type-projection.md @@ -1,18 +1,21 @@ --- layout: doc-page -title: "Dropped: General Type Projection" -nightlyOf: https://docs.scala-lang.org/scala3/reference/dropped-features/type-projection.html +title: "Tightened Type Projection" +nightlyOf: https://docs.scala-lang.org/scala3/reference/changed-features/type-projection.html --- -Scala so far allowed general type projection `T#A` where `T` is an arbitrary type -and `A` names a type member of `T`. +Scala 2 allowed general type projection `T#A` where `T` is an arbitrary type and `A` names a type member of `T`. +This turns out to be [unsound](https://github.com/scala/scala3/issues/1050) (at least when combined with other Scala 3 features). -Scala 3 disallows this if `T` is an abstract type (class types and type aliases -are fine). This change was made because unrestricted type projection -is [unsound](https://github.com/scala/scala3/issues/1050). - -This restriction rules out the [type-level encoding of a combinator -calculus](https://michid.wordpress.com/2010/01/29/scala-type-level-encoding-of-the-ski-calculus/). +To remedy this, Scala 3 only allows type projection if `T` is a concrete type (any type which is not abstract), an example for such a type would be a class type (`class T`). +A type is abstract if it is: +* An abstract type member (`type T` without `= SomeType`) +* A type parameter (`[T]`) +* An alias to an abstract type (`type T = SomeAbstactType`). +There are no restriction on `A` appart from the fact it has to be a member type of `T`, for example a subclass (`class T { class A }`). To rewrite code using type projections on abstract types, consider using path-dependent types or implicit parameters. + +This restriction rules out the [type-level encoding of a combinator +calculus](https://michid.wordpress.com/2010/01/29/scala-type-level-encoding-of-the-ski-calculus/). \ No newline at end of file From c61d0b4fe3a2945287f5ea7e5dbd6f8730777bba Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Sat, 15 Mar 2025 18:04:17 +0100 Subject: [PATCH 206/505] Re-move type-projection [Cherry-picked f963f17a9fa5c11a8ba22c12c31506858bb5832a] --- .../{changed-features => dropped-features}/type-projection.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/_docs/reference/{changed-features => dropped-features}/type-projection.md (100%) diff --git a/docs/_docs/reference/changed-features/type-projection.md b/docs/_docs/reference/dropped-features/type-projection.md similarity index 100% rename from docs/_docs/reference/changed-features/type-projection.md rename to docs/_docs/reference/dropped-features/type-projection.md From 99117640a96541b74e2f264edcdaaa7a54d4753f Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Sat, 15 Mar 2025 18:07:59 +0100 Subject: [PATCH 207/505] De-rename the page [Cherry-picked 126fc253fd22a089c3e8d109f4a3e4958d02310c] --- docs/_docs/reference/dropped-features/type-projection.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/_docs/reference/dropped-features/type-projection.md b/docs/_docs/reference/dropped-features/type-projection.md index 32c56029ce51..3dbba9d9fa89 100644 --- a/docs/_docs/reference/dropped-features/type-projection.md +++ b/docs/_docs/reference/dropped-features/type-projection.md @@ -1,7 +1,7 @@ --- layout: doc-page -title: "Tightened Type Projection" -nightlyOf: https://docs.scala-lang.org/scala3/reference/changed-features/type-projection.html +title: "Dropped: General Type Projection" +nightlyOf: https://docs.scala-lang.org/scala3/reference/dropped-features/type-projection.html --- Scala 2 allowed general type projection `T#A` where `T` is an arbitrary type and `A` names a type member of `T`. From 671e601beaf938ab3bd2dec2a50c295034c615d3 Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Sat, 15 Mar 2025 18:08:10 +0100 Subject: [PATCH 208/505] Fix typo [Cherry-picked a9830ea1334195cb433cece929215dafa92d6857] --- docs/_docs/reference/dropped-features/type-projection.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/_docs/reference/dropped-features/type-projection.md b/docs/_docs/reference/dropped-features/type-projection.md index 3dbba9d9fa89..9b9f643ceb6e 100644 --- a/docs/_docs/reference/dropped-features/type-projection.md +++ b/docs/_docs/reference/dropped-features/type-projection.md @@ -11,8 +11,8 @@ To remedy this, Scala 3 only allows type projection if `T` is a concrete type (a A type is abstract if it is: * An abstract type member (`type T` without `= SomeType`) * A type parameter (`[T]`) -* An alias to an abstract type (`type T = SomeAbstactType`). -There are no restriction on `A` appart from the fact it has to be a member type of `T`, for example a subclass (`class T { class A }`). +* An alias to an abstract type (`type T = SomeAbstractType`). +There are no restriction on `A` apart from the fact it has to be a member type of `T`, for example a subclass (`class T { class A }`). To rewrite code using type projections on abstract types, consider using path-dependent types or implicit parameters. From f5503ada0ec98177d6f015ada5ea9be840e7ae23 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Sat, 15 Mar 2025 19:35:00 +0100 Subject: [PATCH 209/505] feature: Skip auto importing symbols we know are wrong in current context [Cherry-picked 9f2280566e1a0804961d96e5937c11fc4be5a470] --- .../dotty/tools/pc/AutoImportsProvider.scala | 30 ++++++++- .../dotty/tools/pc/PcDefinitionProvider.scala | 2 +- .../pc/tests/edit/AutoImportsSuite.scala | 63 +++++++++++++++++++ 3 files changed, 91 insertions(+), 4 deletions(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/AutoImportsProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/AutoImportsProvider.scala index e35556ad11c9..d30ab813f9f2 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/AutoImportsProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/AutoImportsProvider.scala @@ -10,6 +10,7 @@ import scala.meta.pc.* import dotty.tools.dotc.ast.tpd.* import dotty.tools.dotc.core.Symbols.* +import dotty.tools.dotc.core.StdNames.* import dotty.tools.dotc.interactive.Interactive import dotty.tools.dotc.interactive.InteractiveDriver import dotty.tools.dotc.util.SourceFile @@ -17,6 +18,7 @@ import dotty.tools.pc.completions.CompletionPos import dotty.tools.pc.utils.InteractiveEnrichments.* import org.eclipse.lsp4j as l +import dotty.tools.dotc.core.Flags.Method final class AutoImportsProvider( search: SymbolSearch, @@ -47,6 +49,17 @@ final class AutoImportsProvider( ) import indexedContext.ctx + + def correctInTreeContext(sym: Symbol) = path match + case (_: Ident) :: (sel: Select) :: _ => + sym.info.allMembers.exists(_.name == sel.name) + case (_: Ident) :: (_: Apply) :: _ if !sym.is(Method) => + def applyInObject = + sym.companionModule.info.allMembers.exists(_.name == nme.apply) + def applyInClass = sym.info.allMembers.exists(_.name == nme.apply) + applyInClass || applyInObject + case _ => true + val isSeen = mutable.Set.empty[String] val symbols = List.newBuilder[Symbol] def visit(sym: Symbol): Boolean = @@ -90,13 +103,24 @@ final class AutoImportsProvider( end match end mkEdit - for + val all = for sym <- results edits <- mkEdit(sym) - yield AutoImportsResultImpl( + yield (AutoImportsResultImpl( sym.owner.showFullName, edits.asJava - ) + ), sym) + + all match + case (onlyResult, _) :: Nil => List(onlyResult) + case Nil => Nil + case moreResults => + val moreExact = moreResults.filter { case (_, sym) => + correctInTreeContext(sym) + } + if moreExact.nonEmpty then moreExact.map(_._1) + else moreResults.map(_._1) + else List.empty end if end autoImports diff --git a/presentation-compiler/src/main/dotty/tools/pc/PcDefinitionProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/PcDefinitionProvider.scala index 9fbaa8dcd16d..a2e9b05e0610 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/PcDefinitionProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/PcDefinitionProvider.scala @@ -149,7 +149,7 @@ class PcDefinitionProvider( case srcTree if srcTree.namePos.exists => new Location(params.uri().toString(), srcTree.namePos.toLsp) .toList - else search.definition(semanticdbSymbol, uri).asScala.toList + else search.definition(semanticdbSymbol, uri).nn.asScala.toList def semanticSymbolsSorted( syms: List[Symbol] diff --git a/presentation-compiler/test/dotty/tools/pc/tests/edit/AutoImportsSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/edit/AutoImportsSuite.scala index 3bb5bfea7bc0..bf568bc0636b 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/edit/AutoImportsSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/edit/AutoImportsSuite.scala @@ -12,6 +12,69 @@ class AutoImportsSuite extends BaseAutoImportsSuite: | <>.successful(2) |} |""".stripMargin, + """|scala.concurrent + |""".stripMargin + ) + + @Test def `basic-apply` = + check( + """|object A { + | <>(2) + |} + |""".stripMargin, + """|scala.concurrent + |""".stripMargin, + ) + + @Test def `basic-function-apply` = + check( + """| + |object ForgeFor{ + | def importMe(): Int = ??? + |} + |object ForgeFor2{ + | case class importMe() + |} + | + | + |object test2 { + | <>() + |} + |""".stripMargin, + """|ForgeFor2 + |ForgeFor + |""".stripMargin + ) + + @Test def `basic-apply-wrong` = + check( + """|object A { + | new <>(2) + |} + |""".stripMargin, + """|scala.concurrent + |java.util.concurrent + |""".stripMargin + ) + + @Test def `basic-fuzzy` = + check( + """|object A { + | <>.thisMethodDoesntExist(2) + |} + |""".stripMargin, + """|scala.concurrent + |java.util.concurrent + |""".stripMargin + ) + + @Test def `typed-simple` = + check( + """|object A { + | import scala.concurrent.Promise + | val fut: <> = Promise[Unit]().future + |} + |""".stripMargin, """|scala.concurrent |java.util.concurrent |""".stripMargin From f3239d679cf72731e9977d7f9782b981337c84f7 Mon Sep 17 00:00:00 2001 From: Jan Chyb <48855024+jchyb@users.noreply.github.com> Date: Mon, 17 Mar 2025 12:57:44 +0100 Subject: [PATCH 210/505] Fail compilation if multiple conflicting top-level private defs/vals are in the same package (#22759) Now the private top level definitions act basically the same as package private (which is the same behavior as private objects/classes), as that is what the reference implies, and it helps us avoid ambiguous method/value selections. --- compiler/src/dotty/tools/dotc/typer/Namer.scala | 12 ++++++------ tests/neg/i22721.check | 6 ++++++ tests/neg/i22721/test1.scala | 4 ++++ tests/neg/i22721/test2.scala | 4 ++++ tests/neg/toplevel-overload/moredefs_1.scala | 2 +- 5 files changed, 21 insertions(+), 7 deletions(-) create mode 100644 tests/neg/i22721.check create mode 100644 tests/neg/i22721/test1.scala create mode 100644 tests/neg/i22721/test2.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index a47a0a61c9d4..542ea04442ff 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -131,7 +131,7 @@ class Namer { typer: Typer => * The logic here is very subtle and fragile due to the fact that * we are not allowed to force anything. */ - def checkNoConflict(name: Name, isPrivate: Boolean, span: Span)(using Context): Name = + def checkNoConflict(name: Name, span: Span)(using Context): Name = val owner = ctx.owner var conflictsDetected = false @@ -166,7 +166,7 @@ class Namer { typer: Typer => def preExisting = ctx.effectiveScope.lookup(name) if (!owner.isClass || name.isTypeName) && preExisting.exists then conflict(preExisting) - else if owner.isPackageObject && !isPrivate && name != nme.CONSTRUCTOR then + else if owner.isPackageObject && name != nme.CONSTRUCTOR then checkNoConflictIn(owner.owner) for pkgObj <- pkgObjs(owner.owner) if pkgObj != owner do checkNoConflictIn(pkgObj) @@ -242,7 +242,7 @@ class Namer { typer: Typer => tree match { case tree: TypeDef if tree.isClassDef => val flags = checkFlags(tree.mods.flags) - val name = checkNoConflict(tree.name, flags.is(Private), tree.span).asTypeName + val name = checkNoConflict(tree.name, tree.span).asTypeName val cls = createOrRefine[ClassSymbol](tree, name, flags, ctx.owner, cls => adjustIfModule(new ClassCompleter(cls, tree)(ctx), tree), @@ -251,7 +251,7 @@ class Namer { typer: Typer => cls case tree: MemberDef => var flags = checkFlags(tree.mods.flags) - val name = checkNoConflict(tree.name, flags.is(Private), tree.span) + val name = checkNoConflict(tree.name, tree.span) tree match case tree: ValOrDefDef => if tree.isInstanceOf[ValDef] && !flags.is(Param) && name.endsWith("_=") then @@ -1217,7 +1217,7 @@ class Namer { typer: Typer => val hasDefaults = sym.hasDefaultParams // compute here to ensure HasDefaultParams and NoDefaultParams flags are set val forwarder = if mbr.isType then - val forwarderName = checkNoConflict(alias.toTypeName, isPrivate = false, span) + val forwarderName = checkNoConflict(alias.toTypeName, span) var target = pathType.select(sym) if target.typeParams.nonEmpty then target = target.EtaExpand(target.typeParams) @@ -1271,7 +1271,7 @@ class Namer { typer: Typer => (EmptyFlags, mbrInfo) var mbrFlags = MandatoryExportTermFlags | maybeStable | (sym.flags & RetainedExportTermFlags) if pathMethod.exists then mbrFlags |= ExtensionMethod - val forwarderName = checkNoConflict(alias, isPrivate = false, span) + val forwarderName = checkNoConflict(alias, span) newSymbol(cls, forwarderName, mbrFlags, mbrInfo, coord = span) forwarder.info = avoidPrivateLeaks(forwarder) diff --git a/tests/neg/i22721.check b/tests/neg/i22721.check new file mode 100644 index 000000000000..44b0749f3262 --- /dev/null +++ b/tests/neg/i22721.check @@ -0,0 +1,6 @@ +-- [E161] Naming Error: tests/neg/i22721/test2.scala:3:12 -------------------------------------------------------------- +3 |private def foobar: Int = 0 // error + |^^^^^^^^^^^^^^^^^^^^^^^^^^^ + |foobar is already defined as method foobar in tests/neg/i22721/test1.scala + | + |Note that overloaded methods must all be defined in the same group of toplevel definitions diff --git a/tests/neg/i22721/test1.scala b/tests/neg/i22721/test1.scala new file mode 100644 index 000000000000..b3f1b1fba690 --- /dev/null +++ b/tests/neg/i22721/test1.scala @@ -0,0 +1,4 @@ +package example + +private def foobar: String = "foo" +object test1 { def x = foobar } diff --git a/tests/neg/i22721/test2.scala b/tests/neg/i22721/test2.scala new file mode 100644 index 000000000000..c70a42894dcd --- /dev/null +++ b/tests/neg/i22721/test2.scala @@ -0,0 +1,4 @@ +package example + +private def foobar: Int = 0 // error +object test2 { def x = foobar } diff --git a/tests/neg/toplevel-overload/moredefs_1.scala b/tests/neg/toplevel-overload/moredefs_1.scala index 5ba8cfc52078..74cdd3ac1bb6 100644 --- a/tests/neg/toplevel-overload/moredefs_1.scala +++ b/tests/neg/toplevel-overload/moredefs_1.scala @@ -2,4 +2,4 @@ trait B def f(x: B) = s"B" // error: has already been compiled -private def g(): Unit = () // OK, since it is private \ No newline at end of file +private def g(): Unit = () // error: has already been compiled (def is visible in package) \ No newline at end of file From 7b68a5eaaf3d3c9bd0c49ab623b668befa4e9522 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Sun, 27 Apr 2025 12:52:29 +0200 Subject: [PATCH 211/505] Fail compilation if multiple conflicting top-level private defs/vals are in the same package (#22759) Now the private top level definitions act basically the same as package private (which is the same behavior as private objects/classes), as that is what the reference implies, and it helps us avoid ambiguous method/value selections. [Cherry-picked 8fe16fe17819ebd172dd7bb4ed1d8f9080e78f16][modified] From 1d321be85efe59423c706a78f6f5af0fb063c365 Mon Sep 17 00:00:00 2001 From: Natsu Kagami Date: Mon, 17 Mar 2025 18:39:27 +0100 Subject: [PATCH 212/505] Show the Autofill completion case as what would be auto-filled (#22819) Partial Fix for scalameta/metals#7274 We have in our completion provider an option to automatically fill a case class constructor with named parameters: ```scala case class A(x: Int, y: Int) val a = A(@@) ^^ // would fill in here val a = A(x = ???, y = ???) // ^^^ ^^^ cursor marks added, so tabs can be used to move between the fields ``` However previously it was labeled `Autofill with default values`, which would never pass editors' filters based on the current state of input (most likely the name of a field). The only way to find this option was to type something matching the `Autofill with default values` label, which explains the `auto` in the above issue. We now provide the actual provided fields as the label, so the above would show `x = ???, y = ???` instead, which is both more intuitive for the user, and more friendly to editors. [Cherry-picked 744ba922a1729e7670a0db6de981932e60b2b56e] --- .../tools/pc/completions/CompletionValue.scala | 4 ++-- .../tools/pc/completions/NamedArgCompletions.scala | 9 ++++++++- .../pc/tests/completion/CompletionArgSuite.scala | 13 +++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/completions/CompletionValue.scala b/presentation-compiler/src/main/dotty/tools/pc/completions/CompletionValue.scala index 90b285bffb3a..05d97972d76e 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/completions/CompletionValue.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/completions/CompletionValue.scala @@ -261,13 +261,13 @@ object CompletionValue: end NamedArg case class Autofill( - value: String + value: String, + override val label: String, ) extends CompletionValue: override def completionItemKind(using Context): CompletionItemKind = CompletionItemKind.Enum override def completionItemDataKind: Integer = CompletionSource.OverrideKind.ordinal override def insertText: Option[String] = Some(value) - override def label: String = "Autofill with default values" case class Keyword(label: String, override val insertText: Option[String]) extends CompletionValue: diff --git a/presentation-compiler/src/main/dotty/tools/pc/completions/NamedArgCompletions.scala b/presentation-compiler/src/main/dotty/tools/pc/completions/NamedArgCompletions.scala index dd3a910beb4f..a21706b9e36e 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/completions/NamedArgCompletions.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/completions/NamedArgCompletions.scala @@ -339,9 +339,16 @@ object NamedArgCompletions: s"${param.nameBackticked.replace("$", "$$")} = $${${index + 1}${findDefaultValue(param)}}" } .mkString(", ") + val labelText = allParams + .collect { + case param if !param.symbol.is(Flags.HasDefault) => + s"${param.nameBackticked.replace("$", "$$")} = ???" + } + .mkString(", ") List( CompletionValue.Autofill( - editText + editText, + labelText, ) ) else List.empty diff --git a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionArgSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionArgSuite.scala index dc81d2596c6f..e5f2d31ad808 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionArgSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionArgSuite.scala @@ -1128,3 +1128,16 @@ class CompletionArgSuite extends BaseCompletionSuite: """x: Int |x = : Any""".stripMargin, ) + + @Test def `autofill-arguments-case-class` = + check( + """ + |case class A(x: Int, y: Int) + | + |def main() = + | A(x@@) + |""".stripMargin, + """x = : Int + |x = ???, y = ???""".stripMargin, + // this looks strange due to the Autofill message belonging to the description + ) From 8929cc8ffc343e38865ffbfd46fa856e14050512 Mon Sep 17 00:00:00 2001 From: Natsu Kagami Date: Wed, 19 Mar 2025 09:46:10 +0100 Subject: [PATCH 213/505] Ignore ending `$` when looking at end marker names (#22798) ## Fix scalameta/metals#7246 - Add a test for renaming local objects - Drop ending `$` marker when looking for end marker names [Cherry-picked 8027996fa50b0861983c466082df0eed6efba687] --- .../src/main/dotty/tools/pc/PcCollector.scala | 2 +- .../dotty/tools/pc/tests/edit/PcRenameSuite.scala | 11 +++++++++++ .../tools/pc/tests/tokens/SemanticTokensSuite.scala | 13 +++++++++++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/presentation-compiler/src/main/dotty/tools/pc/PcCollector.scala b/presentation-compiler/src/main/dotty/tools/pc/PcCollector.scala index 1ebfd405768e..f3fd7c8738d5 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/PcCollector.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/PcCollector.scala @@ -315,7 +315,7 @@ object EndMarker: def getPosition(df: NamedDefTree, pos: SourcePosition, sourceText: String)( implicit ct: Context ): Option[SourcePosition] = - val name = df.name.toString() + val name = df.name.toString().stripSuffix("$") val endMarkerLine = sourceText.slice(df.span.start, df.span.end).split('\n').last val index = endMarkerLine.length() - name.length() diff --git a/presentation-compiler/test/dotty/tools/pc/tests/edit/PcRenameSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/edit/PcRenameSuite.scala index 3226018f88d4..50806322b09e 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/edit/PcRenameSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/edit/PcRenameSuite.scala @@ -534,3 +534,14 @@ class PcRenameSuite extends BasePcRenameSuite: |""".stripMargin, wrap = false ) + + @Test def `local-object-with-end-rename` = + check( + """|def bar = + | object <>: + | def aaa = ??? + | end <> + | 1 + |""".stripMargin, + wrap = false + ) diff --git a/presentation-compiler/test/dotty/tools/pc/tests/tokens/SemanticTokensSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/tokens/SemanticTokensSuite.scala index fd90a8dfaca0..9f8d82020806 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/tokens/SemanticTokensSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/tokens/SemanticTokensSuite.scala @@ -258,7 +258,7 @@ class SemanticTokensSuite extends BaseSemanticTokensSuite: | } = new: | def <>/*method,definition*/ = "4.0" | <>/*variable,readonly*/.<>/*method*/ - |end StructuralTypes + |end <>/*class,definition*/ |""".stripMargin ) @@ -431,4 +431,13 @@ class SemanticTokensSuite extends BaseSemanticTokensSuite: | <>/*method*/[<