Skip to content

Commit 1d36e6e

Browse files
authored
Merge pull request #550 from scala/backport-lts-3.3-23559
Backport "Warn if implicit default shadows given" to 3.3 LTS
2 parents 6501bdb + 2eb4a9f commit 1d36e6e

File tree

12 files changed

+98
-20
lines changed

12 files changed

+98
-20
lines changed

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ private sealed trait WarningSettings:
175175
private val WNonUnitStatement = BooleanSetting("-Wnonunit-statement", "Warn when block statements are non-Unit expressions.")
176176
private val WenumCommentDiscard = BooleanSetting("-Wenum-comment-discard", "Warn when a comment ambiguously assigned to multiple enum cases is discarded.")
177177
private val WtoStringInterpolated = BooleanSetting("-Wtostring-interpolated", "Warn a standard interpolator used toString on a reference type.")
178+
private val WrecurseWithDefault = BooleanSetting("-Wrecurse-with-default", "Warn when a method calls itself with a default argument.")
178179
private val Wunused: Setting[List[ChoiceWithHelp[String]]] = MultiChoiceHelpSetting(
179180
name = "-Wunused",
180181
helpArg = "warning",
@@ -292,6 +293,7 @@ private sealed trait WarningSettings:
292293
def nonUnitStatement(using Context): Boolean = allOr(WNonUnitStatement)
293294
def enumCommentDiscard(using Context): Boolean = allOr(WenumCommentDiscard)
294295
def toStringInterpolated(using Context): Boolean = allOr(WtoStringInterpolated)
296+
def recurseWithDefault(using Context): Boolean = allOr(WrecurseWithDefault)
295297
def checkInit(using Context): Boolean = allOr(YcheckInit)
296298

297299
/** -X "Extended" or "Advanced" settings */

compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,8 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
233233
case ErasedNotPureID // errorNumber: 217
234234
case IllegalErasedDefID // errorNumber: 218
235235
case CannotInstantiateQuotedTypeVarID // errorNumber: 219
236+
case DefaultShadowsGivenID // errorNumber: 220
237+
case RecurseWithDefaultID // errorNumber: 221
236238

237239
def errorNumber = ordinal - 1
238240

compiler/src/dotty/tools/dotc/reporting/messages.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3307,3 +3307,15 @@ final class NamedPatternNotApplicable(selectorType: Type)(using Context) extends
33073307
i"Named patterns cannot be used with $selectorType, because it is not a named tuple or case class"
33083308

33093309
override protected def explain(using Context): String = ""
3310+
3311+
final class DefaultShadowsGiven(name: Name)(using Context) extends TypeMsg(DefaultShadowsGivenID):
3312+
override protected def msg(using Context): String =
3313+
i"Argument for implicit parameter $name was supplied using a default argument."
3314+
override protected def explain(using Context): String =
3315+
"Usually the given in scope is intended, but you must specify it after explicit `using`."
3316+
3317+
final class RecurseWithDefault(name: Name)(using Context) extends TypeMsg(RecurseWithDefaultID):
3318+
override protected def msg(using Context): String =
3319+
i"Recursive call used a default argument for parameter $name."
3320+
override protected def explain(using Context): String =
3321+
"It's more explicit to pass current or modified arguments in a recursion."

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ package transform
44
import ast.{TreeTypeMap, tpd}
55
import config.Printers.tailrec
66
import core.*
7-
import Contexts.*, Flags.*, Symbols.*, Decorators.em
7+
import Contexts.*, Flags.*, Symbols.*, Decorators.*
88
import Constants.Constant
9-
import NameKinds.{TailLabelName, TailLocalName, TailTempName}
9+
import NameKinds.{DefaultGetterName, TailLabelName, TailLocalName, TailTempName}
1010
import StdNames.nme
1111
import reporting.*
1212
import transform.MegaPhase.MiniPhase
@@ -323,7 +323,14 @@ class TailRec extends MiniPhase {
323323
method.matches(calledMethod) &&
324324
enclosingClass.appliedRef.widen <:< prefix.tpe.widenDealias
325325

326-
if (isRecursiveCall)
326+
if isRecursiveCall then
327+
if ctx.settings.Whas.recurseWithDefault then
328+
tree.args.find(_.symbol.name.is(DefaultGetterName)) match
329+
case Some(arg) =>
330+
val DefaultGetterName(_, index) = arg.symbol.name: @unchecked
331+
report.warning(RecurseWithDefault(calledMethod.info.firstParamNames(index)), tree.srcPos)
332+
case _ =>
333+
327334
if (inTailPosition) {
328335
tailrec.println("Rewriting tail recursive call: " + tree.span)
329336
rewrote = true

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,11 @@ trait Applications extends Compatibility {
674674
def implicitArg = implicitArgTree(formal, appPos.span)
675675

676676
if !defaultArg.isEmpty then
677+
if methodType.isImplicitMethod && ctx.mode.is(Mode.ImplicitsEnabled)
678+
&& !inferImplicitArg(formal, appPos.span).tpe.isError
679+
then
680+
report.warning(DefaultShadowsGiven(methodType.paramNames(n)), appPos)
681+
677682
defaultArg.tpe.widen match
678683
case _: MethodOrPoly if testOnly => matchArgs(args1, formals1, n + 1)
679684
case _ => matchArgs(args1, addTyped(treeToArg(defaultArg)), n + 1)

scaladoc/src/dotty/tools/scaladoc/tasty/TypesSupport.scala

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ package tasty
44
import scala.jdk.CollectionConverters._
55

66
import scala.quoted._
7+
import scala.annotation.*
78

8-
import NameNormalizer._
9-
import SyntheticsSupport._
9+
import NameNormalizer.*
10+
import SyntheticsSupport.*
1011

1112
trait TypesSupport:
1213
self: TastyParser =>
@@ -141,24 +142,24 @@ trait TypesSupport:
141142
.reduceLeftOption((acc: SSignature, elem: SSignature) => acc ++ plain(", ").l ++ elem).getOrElse(List())
142143
++ plain(")").l
143144

144-
def parseRefinedElem(name: String, info: TypeRepr, polyTyped: SSignature = Nil): SSignature = ( info match {
145+
def parseRefinedElem(name: String, info: TypeRepr, polyTyped: SSignature = Nil): SSignature =
146+
val ssig = info match
145147
case m: MethodType => {
146148
val paramList = getParamList(m)
147149
keyword("def ").l ++ plain(name).l ++ polyTyped ++ paramList ++ plain(": ").l ++ inner(m.resType)
148150
}
149-
case t: PolyType => {
151+
case t: PolyType =>
150152
val paramBounds = getParamBounds(t)
151-
val parsedMethod = parseRefinedElem(name, t.resType)
152-
if (!paramBounds.isEmpty){
153+
if !paramBounds.isEmpty then
153154
parseRefinedElem(name, t.resType, plain("[").l ++ paramBounds ++ plain("]").l)
154-
} else parseRefinedElem(name, t.resType)
155-
}
155+
else parseRefinedElem(name, t.resType, polyTyped = Nil)
156156
case ByNameType(tp) => keyword("def ").l ++ plain(s"$name: ").l ++ inner(tp)
157157
case t: TypeBounds => keyword("type ").l ++ plain(name).l ++ inner(t)
158158
case t: TypeRef => keyword("val ").l ++ plain(s"$name: ").l ++ inner(t)
159159
case t: TermRef => keyword("val ").l ++ plain(s"$name: ").l ++ inner(t)
160160
case other => noSupported(s"Not supported type in refinement $info")
161-
} ) ++ plain("; ").l
161+
162+
ssig ++ plain("; ").l
162163

163164
def parsePolyFunction(info: TypeRepr): SSignature = info match {
164165
case t: PolyType =>
@@ -225,6 +226,7 @@ trait TypesSupport:
225226
}) ++ plain("]").l
226227

227228
case tp @ TypeRef(qual, typeName) =>
229+
inline def wrapping = shouldWrapInParens(inner = qual, outer = tp, isLeft = true)
228230
qual match {
229231
case r: RecursiveThis => tpe(s"this.$typeName").l
230232
case t if skipPrefix(t, elideThis) =>
@@ -245,17 +247,17 @@ trait TypesSupport:
245247
case _ => tpe(tp.typeSymbol)
246248
case Some(_) => tpe(tp.typeSymbol)
247249
case None =>
248-
val sig = inParens(inner(qual)(using skipTypeSuffix = true), shouldWrapInParens(qual, tp, true))
250+
val sig = inParens(inner(qual)(using indent = indent, skipTypeSuffix = true), wrapping)
249251
sig ++ plain(".").l ++ tpe(tp.typeSymbol)
250252
case _ =>
251-
val sig = inParens(inner(qual), shouldWrapInParens(qual, tp, true))
253+
val sig = inParens(inner(qual, skipThisTypePrefix), wrapping)
252254
sig ++ keyword("#").l ++ tpe(tp.typeSymbol)
253255
}
254256

255257
case tr @ TermRef(qual, typeName) =>
256258
val prefix = qual match
257259
case t if skipPrefix(t, elideThis) => Nil
258-
case tp => inner(tp)(using skipTypeSuffix = true) ++ plain(".").l
260+
case tp => inner(tp)(using indent = indent, skipTypeSuffix = true) ++ plain(".").l
259261
val suffix = if skipTypeSuffix then Nil else List(plain("."), keyword("type"))
260262
val typeSig = tr.termSymbol.tree match
261263
case vd: ValDef if tr.termSymbol.flags.is(Flags.Module) =>
@@ -274,9 +276,9 @@ trait TypesSupport:
274276
val spaces = " " * (indent)
275277
val casesTexts = cases.flatMap {
276278
case MatchCase(from, to) =>
277-
keyword(caseSpaces + "case ").l ++ inner(from) ++ keyword(" => ").l ++ inner(to)(using indent = indent + 2) ++ plain("\n").l
279+
keyword(caseSpaces + "case ").l ++ inner(from) ++ keyword(" => ").l ++ inner(to)(using indent = indent + 2, skipTypeSuffix = skipTypeSuffix) ++ plain("\n").l
278280
case TypeLambda(_, _, MatchCase(from, to)) =>
279-
keyword(caseSpaces + "case ").l ++ inner(from) ++ keyword(" => ").l ++ inner(to)(using indent = indent + 2) ++ plain("\n").l
281+
keyword(caseSpaces + "case ").l ++ inner(from) ++ keyword(" => ").l ++ inner(to)(using indent = indent + 2, skipTypeSuffix = skipTypeSuffix) ++ plain("\n").l
280282
}
281283
inner(sc) ++ keyword(" match ").l ++ plain("{\n").l ++ casesTexts ++ plain(spaces + "}").l
282284

tests/neg/19414-desugared.check renamed to tests/neg/i19414-desugared.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
-- [E172] Type Error: tests/neg/19414-desugared.scala:22:34 ------------------------------------------------------------
1+
-- [E172] Type Error: tests/neg/i19414-desugared.scala:22:34 -----------------------------------------------------------
22
22 | summon[BodySerializer[JsObject]] // error: Ambiguous given instances
33
| ^
44
|No best given instance of type BodySerializer[JsObject] was found for parameter x of method summon in object Predef.
File renamed without changes.

tests/neg/19414.check renamed to tests/neg/i19414.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
-- [E172] Type Error: tests/neg/19414.scala:15:34 ----------------------------------------------------------------------
1+
-- [E172] Type Error: tests/neg/i19414.scala:15:34 ---------------------------------------------------------------------
22
15 | summon[BodySerializer[JsObject]] // error: Ambiguous given instances
33
| ^
44
|No best given instance of type BodySerializer[JsObject] was found for parameter x of method summon in object Predef.

tests/neg/19414.scala renamed to tests/neg/i19414.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class Printer
99
given Writer[JsValue] = ???
1010
given Writer[JsObject] = ???
1111

12-
given [B: Writer](using printer: Printer = new Printer): BodySerializer[B] = ???
12+
given [B: Writer] => (printer: Printer = new Printer) => BodySerializer[B] = ???
1313

1414
def f: Unit =
1515
summon[BodySerializer[JsObject]] // error: Ambiguous given instances

0 commit comments

Comments
 (0)