Skip to content

Commit 1e07f07

Browse files
authored
Merge pull request #419 from scala/backport-lts-3.3-23147
Backport "Improve Unit ascription escape hatch" to 3.3 LTS
2 parents 651fad4 + f0eb6e3 commit 1e07f07

File tree

13 files changed

+79
-41
lines changed

13 files changed

+79
-41
lines changed

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,19 @@ trait TreeInfo[T <: Untyped] { self: Trees.Instance[T] =>
262262
case _ => false
263263
}
264264

265+
/** Expression was written `e: Unit` to quell warnings. Looks into adapted tree. */
266+
def isAscribedToUnit(tree: Tree): Boolean =
267+
import typer.Typer.AscribedToUnit
268+
tree.hasAttachment(AscribedToUnit)
269+
|| {
270+
def loop(tree: Tree): Boolean = tree match
271+
case Apply(fn, _) => fn.hasAttachment(AscribedToUnit) || loop(fn)
272+
case TypeApply(fn, _) => fn.hasAttachment(AscribedToUnit) || loop(fn)
273+
case Block(_, expr) => expr.hasAttachment(AscribedToUnit) || loop(expr)
274+
case _ => false
275+
loop(tree)
276+
}
277+
265278
/** Does this CaseDef catch Throwable? */
266279
def catchesThrowable(cdef: CaseDef)(using Context): Boolean =
267280
catchesAllOf(cdef, defn.ThrowableType)

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
632632
val checkedType = checkNotShadowed(ownType)
633633
val tree1 = checkedType match
634634
case checkedType: NamedType if !prefixIsElidable(checkedType) =>
635-
ref(checkedType).withSpan(tree.span)
635+
ref(checkedType).withSpan(tree.span).withAttachmentsFrom(tree)
636636
case _ =>
637637
tree.withType(checkedType)
638638
val tree2 = toNotNullTermRef(tree1, pt)
@@ -4236,7 +4236,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
42364236
&& !ctx.isAfterTyper
42374237
&& !tree.isInstanceOf[Inlined]
42384238
&& !isThisTypeResult(tree)
4239-
&& !tree.hasAttachment(AscribedToUnit) then
4239+
&& !isAscribedToUnit(tree)
4240+
then
42404241
report.warning(ValueDiscarding(tree.tpe), tree.srcPos)
42414242

42424243
return tpd.Block(tree1 :: Nil, unitLiteral)

presentation-compiler/src/main/dotty/tools/pc/CompletionItemResolver.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ object CompletionItemResolver extends ItemResolver:
6262
if companion == NoSymbol || gsym.is(JavaDefined) then
6363
if gsymDoc.isEmpty() then
6464
if gsym.isAliasType then
65-
fullDocstring(gsym.info.deepDealias.typeSymbol, search)
65+
fullDocstring(gsym.info.deepDealiasAndSimplify.typeSymbol, search)
6666
else if gsym.is(Method) then
6767
gsym.info.finalResultType match
6868
case tr @ TermRef(_, sym) =>

presentation-compiler/src/main/dotty/tools/pc/HoverProvider.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ object HoverProvider:
108108
if symbol.name == nme.selectDynamic || symbol.name == nme.applyDynamic =>
109109
fallbackToDynamics(path, printer, contentType)
110110
case symbolTpes @ ((symbol, tpe, _) :: _) =>
111-
val exprTpw = tpe.widenTermRefExpr.deepDealias
111+
val exprTpw = tpe.widenTermRefExpr.deepDealiasAndSimplify
112112
val hoverString =
113113
tpw match
114114
// https://github.com/lampepfl/dotty/issues/8891
@@ -123,7 +123,7 @@ object HoverProvider:
123123
if tpe != NoType then tpe
124124
else tpw
125125

126-
printer.hoverSymbol(sym, finalTpe.deepDealias)
126+
printer.hoverSymbol(sym, finalTpe.deepDealiasAndSimplify)
127127
end match
128128
end hoverString
129129

@@ -177,7 +177,7 @@ object HoverProvider:
177177
val resultType =
178178
rest match
179179
case Select(_, asInstanceOf) :: TypeApply(_, List(tpe)) :: _ if asInstanceOf == nme.asInstanceOfPM =>
180-
tpe.tpe.widenTermRefExpr.deepDealias
180+
tpe.tpe.widenTermRefExpr.deepDealiasAndSimplify
181181
case _ if n == nme.selectDynamic => tpe.resultType
182182
case _ => tpe
183183

@@ -202,9 +202,9 @@ object HoverProvider:
202202
findRefinement(parent)
203203
case _ => None
204204

205-
val refTpe = sel.typeOpt.widen.deepDealias match
205+
val refTpe = sel.typeOpt.widen.deepDealiasAndSimplify match
206206
case r: RefinedType => Some(r)
207-
case t: (TermRef | TypeProxy) => Some(t.termSymbol.info.deepDealias)
207+
case t: (TermRef | TypeProxy) => Some(t.termSymbol.info.deepDealiasAndSimplify)
208208
case _ => None
209209

210210
refTpe.flatMap(findRefinement).asJava

presentation-compiler/src/main/dotty/tools/pc/InferredTypeProvider.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ final class InferredTypeProvider(
102102
case _ => true
103103
if isInScope(tpe)
104104
then tpe
105-
else tpe.deepDealias
105+
else tpe.deepDealiasAndSimplify
106106

107107
val printer = ShortenedTypePrinter(
108108
symbolSearch,

presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ class PcInlayHintsProvider(
140140
isInScope(tycon) && args.forall(isInScope)
141141
case _ => true
142142
if isInScope(tpe) then tpe
143-
else tpe.deepDealias(using indexedCtx.ctx)
143+
else tpe.deepDealiasAndSimplify(using indexedCtx.ctx)
144144

145145
val dealiased = optDealias(tpe)
146146
val tpeStr = printer.tpe(dealiased)

presentation-compiler/src/main/dotty/tools/pc/SymbolInformationProvider.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import dotty.tools.dotc.core.Flags
1111
import dotty.tools.dotc.core.Names.*
1212
import dotty.tools.dotc.core.StdNames.nme
1313
import dotty.tools.dotc.core.Symbols.*
14-
import dotty.tools.pc.utils.InteractiveEnrichments.deepDealias
14+
import dotty.tools.pc.utils.InteractiveEnrichments.deepDealiasAndSimplify
1515
import dotty.tools.pc.SemanticdbSymbols
1616
import dotty.tools.pc.utils.InteractiveEnrichments.allSymbols
1717
import dotty.tools.pc.utils.InteractiveEnrichments.stripBackticks
@@ -51,7 +51,7 @@ class SymbolInformationProvider(using Context):
5151
collect(classSym)
5252
visited.toList.map(SemanticdbSymbols.symbolName)
5353
val dealisedSymbol =
54-
if sym.isAliasType then sym.info.deepDealias.typeSymbol else sym
54+
if sym.isAliasType then sym.info.deepDealiasAndSimplify.typeSymbol else sym
5555
val classOwner =
5656
sym.ownersIterator.drop(1).find(s => s.isClass || s.is(Flags.Module))
5757
val overridden = sym.denot.allOverriddenSymbols.toList

presentation-compiler/src/main/dotty/tools/pc/completions/MatchCaseCompletions.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ object CaseKeywordCompletion:
9393
case (Ident(v), tpe) => v.decoded == value
9494
case (Select(_, v), tpe) => v.decoded == value
9595
case t => false
96-
.map((_, id) => argPts(id).widen.deepDealias)
96+
.map((_, id) => argPts(id).widen.deepDealiasAndSimplify)
9797
/* Parent is a function expecting a case match expression */
9898
case TreeApply(fun, _) if !fun.tpe.isErroneous =>
9999
fun.tpe.paramInfoss match
@@ -103,12 +103,12 @@ object CaseKeywordCompletion:
103103
) =>
104104
val args = head.argTypes.init
105105
if args.length > 1 then
106-
Some(definitions.tupleType(args).widen.deepDealias)
107-
else args.headOption.map(_.widen.deepDealias)
106+
Some(definitions.tupleType(args).widen.deepDealiasAndSimplify)
107+
else args.headOption.map(_.widen.deepDealiasAndSimplify)
108108
case _ => None
109109
case _ => None
110110
case sel =>
111-
Some(sel.tpe.widen.deepDealias)
111+
Some(sel.tpe.widen.deepDealiasAndSimplify)
112112

113113
selTpe
114114
.collect { case selTpe if selTpe != NoType =>
@@ -279,8 +279,8 @@ object CaseKeywordCompletion:
279279
clientSupportsSnippets
280280
)
281281

282-
val tpeStr = printer.tpe(selector.tpe.widen.deepDealias.bounds.hi)
283-
val tpe = selector.typeOpt.widen.deepDealias.bounds.hi match
282+
val tpeStr = printer.tpe(selector.tpe.widen.deepDealiasAndSimplify.bounds.hi)
283+
val tpe = selector.typeOpt.widen.deepDealiasAndSimplify.bounds.hi match
284284
case tr @ TypeRef(_, _) => tr.underlying
285285
case t => t
286286

presentation-compiler/src/main/dotty/tools/pc/completions/SingletonCompletions.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ object SingletonCompletions:
4242
} yield value
4343

4444
private def collectSingletons(tpe: Type)(using Context): List[Constant] =
45-
tpe.deepDealias match
45+
tpe.deepDealiasAndSimplify match
4646
case ConstantType(value) => List(value)
4747
case OrType(tpe1, tpe2) =>
4848
collectSingletons(tpe1) ++ collectSingletons(tpe2)

presentation-compiler/src/main/dotty/tools/pc/utils/InteractiveEnrichments.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ object InteractiveEnrichments extends CommonMtagsEnrichments:
178178
if sym.is(Module) then sym.companionClass else sym.companionModule
179179

180180
def dealiasType: Symbol =
181-
if sym.isType then sym.info.deepDealias.typeSymbol else sym
181+
if sym.isType then sym.info.deepDealiasAndSimplify.typeSymbol else sym
182182

183183
def nameBackticked: String = nameBackticked(Set.empty[String])
184184

@@ -402,16 +402,16 @@ object InteractiveEnrichments extends CommonMtagsEnrichments:
402402
end extension
403403

404404
extension (tpe: Type)
405-
def deepDealias(using Context): Type =
406-
tpe.dealias match
405+
def deepDealiasAndSimplify(using Context): Type =
406+
val dealiased = tpe.dealias match
407407
case app @ AppliedType(tycon, params) =>
408-
AppliedType(tycon, params.map(_.deepDealias))
408+
AppliedType(tycon, params.map(_.deepDealiasAndSimplify))
409409
case aliasingBounds: AliasingBounds =>
410410
aliasingBounds.derivedAlias(aliasingBounds.alias.deepDealiasAndSimplify)
411411
case TypeBounds(lo, hi) =>
412412
TypeBounds(lo.dealias, hi.dealias)
413413
case RefinedType(parent, name, refinedInfo) =>
414-
RefinedType(parent.dealias, name, refinedInfo.deepDealias)
414+
RefinedType(parent.dealias, name, refinedInfo.deepDealiasAndSimplify)
415415
case dealised => dealised
416416
dealiased.simplified
417417

tests/pos/i20070.scala

Lines changed: 0 additions & 7 deletions
This file was deleted.

tests/warn/warn-value-discard.check

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
27 | mutable.Set.empty[String].remove("") // warn
33
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
44
| discarded non-Unit value of type Boolean. Add `: Unit` to discard silently.
5-
-- [E175] Potential Issue Warning: tests/warn/warn-value-discard.scala:39:41 -------------------------------------------
6-
39 | mutable.Set.empty[String].subtractOne("") // warn
5+
-- [E175] Potential Issue Warning: tests/warn/warn-value-discard.scala:37:41 -------------------------------------------
6+
37 | mutable.Set.empty[String].subtractOne("") // warn
77
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
88
| discarded non-Unit value of type scala.collection.mutable.Set[String]. Add `: Unit` to discard silently.
9-
-- [E175] Potential Issue Warning: tests/warn/warn-value-discard.scala:59:4 --------------------------------------------
10-
59 | mutable.Set.empty[String] += "" // warn
9+
-- [E175] Potential Issue Warning: tests/warn/warn-value-discard.scala:57:4 --------------------------------------------
10+
57 | mutable.Set.empty[String] += "" // warn
1111
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1212
| discarded non-Unit value of type scala.collection.mutable.Set[String]. Add `: Unit` to discard silently.
1313
-- [E175] Potential Issue Warning: tests/warn/warn-value-discard.scala:15:35 -------------------------------------------

tests/warn/warn-value-discard.scala

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,9 @@ class ValueDiscardTest:
2626
// --> Warning
2727
mutable.Set.empty[String].remove("") // warn
2828

29-
// TODO IMHO we don't need to support this,
30-
// as it's just as easy to add a @nowarn annotation as a Unit ascription
31-
//def removeAscribed(): Unit = {
32-
// mutable.Set.empty[String].remove(""): Unit // nowarn
33-
//}
29+
def removeAscribed(): Unit = {
30+
mutable.Set.empty[String].remove(""): Unit // nowarn
31+
}
3432

3533
def subtract(): Unit =
3634
// - Set#subtractOne returns this.type
@@ -63,4 +61,37 @@ class ValueDiscardTest:
6361
// - receiver is a local variable
6462
// --> No warning
6563
val s: mutable.Set[String] = mutable.Set.empty[String]
66-
s += ""
64+
s += ""
65+
66+
// see also tests/warn/21557.scala
67+
class UnitAscription:
68+
import scala.concurrent.*, ExecutionContext.Implicits.given
69+
70+
case class C(c: Int):
71+
def f(i: Int, j: Int = c) = i + j
72+
73+
def f(i: Int, j: Int = 27) = i + j
74+
75+
def g[A]: List[A] = Nil
76+
77+
def i: Int = 42
78+
79+
def `default arg is inline`: Unit =
80+
f(i = 42): Unit // nowarn
81+
82+
def `default arg requires block`: Unit =
83+
C(27).f(i = 42): Unit // nowarn
84+
85+
def `application requires implicit arg`: Unit =
86+
Future(42): Unit // nowarn
87+
88+
def `application requires inferred type arg`: Unit =
89+
g: Unit // nowarn
90+
91+
def `implicit selection from this`: Unit =
92+
i: Unit // nowarn
93+
94+
object UnitAscription:
95+
def g[A]: List[A] = Nil
96+
def `application requires inferred type arg`: Unit =
97+
g: Unit // nowarn UnitAscription.g

0 commit comments

Comments
 (0)