@@ -3306,7 +3306,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
33063306 traverse(xtree :: rest)
33073307 case stat :: rest =>
33083308 val stat1 = typed(stat)(using ctx.exprContext(stat, exprOwner))
3309- if ! checkInterestingResultInStatement (stat1) then checkStatementPurity(stat1)(stat, exprOwner)
3309+ if ! Linter .warnOnInterestingResultInStatement (stat1) then checkStatementPurity(stat1)(stat, exprOwner)
33103310 buf += stat1
33113311 traverse(rest)(using stat1.nullableContext)
33123312 case nil =>
@@ -4372,109 +4372,18 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
43724372 tree match
43734373 case _ : RefTree | _ : Literal
43744374 if ! isVarPattern(tree) && ! (pt <:< tree.tpe) =>
4375- withMode(Mode .GadtConstraintInference ) {
4375+ withMode(Mode .GadtConstraintInference ):
43764376 TypeComparer .constrainPatternType(tree.tpe, pt)
4377- }
4378-
4379- // approximate type params with bounds
4380- def approx = new ApproximatingTypeMap {
4381- var alreadyExpanding : List [TypeRef ] = Nil
4382- def apply (tp : Type ) = tp.dealias match
4383- case tp : TypeRef if ! tp.symbol.isClass =>
4384- if alreadyExpanding contains tp then tp else
4385- val saved = alreadyExpanding
4386- alreadyExpanding ::= tp
4387- val res = expandBounds(tp.info.bounds)
4388- alreadyExpanding = saved
4389- res
4390- case _ =>
4391- mapOver(tp)
4392- }
43934377
4394- // Is it certain that a value of `tree.tpe` is never a subtype of `pt`?
4395- // It is true if either
4396- // - the class of `tree.tpe` and class of `pt` cannot have common subclass, or
4397- // - `tree` is an object or enum value, which cannot possibly be a subtype of `pt`
4398- val isDefiniteNotSubtype = {
4399- val clsA = tree.tpe.widenDealias.classSymbol
4400- val clsB = pt.dealias.classSymbol
4401- clsA.exists && clsB.exists
4402- && clsA != defn.NullClass
4403- && (! clsA.isNumericValueClass && ! clsB.isNumericValueClass) // approximation for numeric conversion and boxing
4404- && ! clsA.asClass.mayHaveCommonChild(clsB.asClass)
4405- || tree.symbol.isOneOf(Module | Enum )
4406- && ! (tree.tpe frozen_<:< pt) // fast track
4407- && ! (tree.tpe frozen_<:< approx(pt))
4408- }
4378+ Linter .warnOnImplausiblePattern(tree, pt)
44094379
4410- if isDefiniteNotSubtype then
4411- // We could check whether `equals` is overridden.
4412- // Reasons for not doing so:
4413- // - it complicates the protocol
4414- // - such code patterns usually implies hidden errors in the code
4415- // - it's safe/sound to reject the code
4416- report.error(TypeMismatch (tree.tpe, pt, Some (tree), " \n pattern type is incompatible with expected type" ), tree.srcPos)
4417- else
4418- val cmp =
4419- untpd.Apply (
4420- untpd.Select (untpd.TypedSplice (tree), nme.EQ ),
4421- untpd.TypedSplice (dummyTreeOfType(pt)))
4422- typedExpr(cmp, defn.BooleanType )
4380+ val cmp =
4381+ untpd.Apply (
4382+ untpd.Select (untpd.TypedSplice (tree), nme.EQ ),
4383+ untpd.TypedSplice (dummyTreeOfType(pt)))
4384+ typedExpr(cmp, defn.BooleanType )
44234385 case _ =>
44244386
4425- private def checkInterestingResultInStatement (t : Tree )(using Context ): Boolean = {
4426- def isUninterestingSymbol (sym : Symbol ): Boolean =
4427- sym == NoSymbol ||
4428- sym.isConstructor ||
4429- sym.is(Package ) ||
4430- sym.isPackageObject ||
4431- sym == defn.BoxedUnitClass ||
4432- sym == defn.AnyClass ||
4433- sym == defn.AnyRefAlias ||
4434- sym == defn.AnyValClass
4435- def isUninterestingType (tpe : Type ): Boolean =
4436- tpe == NoType ||
4437- tpe.typeSymbol == defn.UnitClass ||
4438- defn.isBottomClass(tpe.typeSymbol) ||
4439- tpe =:= defn.UnitType ||
4440- tpe.typeSymbol == defn.BoxedUnitClass ||
4441- tpe =:= defn.AnyValType ||
4442- tpe =:= defn.AnyType ||
4443- tpe =:= defn.AnyRefType
4444- def isJavaApplication (t : Tree ): Boolean = t match {
4445- case Apply (f, _) => f.symbol.is(JavaDefined ) && ! defn.ObjectClass .isSubClass(f.symbol.owner)
4446- case _ => false
4447- }
4448- def checkInterestingShapes (t : Tree ): Boolean = t match {
4449- case If (_, thenpart, elsepart) => checkInterestingShapes(thenpart) || checkInterestingShapes(elsepart)
4450- case Block (_, res) => checkInterestingShapes(res)
4451- case Match (_, cases) => cases.exists(k => checkInterestingShapes(k.body))
4452- case _ => checksForInterestingResult(t)
4453- }
4454- def checksForInterestingResult (t : Tree ): Boolean = (
4455- ! t.isDef // ignore defs
4456- && ! isUninterestingSymbol(t.symbol) // ctors, package, Unit, Any
4457- && ! isUninterestingType(t.tpe) // bottom types, Unit, Any
4458- && ! isThisTypeResult(t) // buf += x
4459- && ! isSuperConstrCall(t) // just a thing
4460- && ! isJavaApplication(t) // Java methods are inherently side-effecting
4461- // && !treeInfo.hasExplicitUnit(t) // suppressed by explicit expr: Unit // TODO Should explicit `: Unit` be added as warning suppression?
4462- )
4463- if ctx.settings.WNonUnitStatement .value && ! ctx.isAfterTyper && checkInterestingShapes(t) then
4464- val where = t match {
4465- case Block (_, res) => res
4466- case If (_, thenpart, Literal (Constant (()))) =>
4467- thenpart match {
4468- case Block (_, res) => res
4469- case _ => thenpart
4470- }
4471- case _ => t
4472- }
4473- report.warning(UnusedNonUnitValue (where.tpe), t.srcPos)
4474- true
4475- else false
4476- }
4477-
44784387 private def checkStatementPurity (tree : tpd.Tree )(original : untpd.Tree , exprOwner : Symbol )(using Context ): Unit =
44794388 if ! tree.tpe.isErroneous
44804389 && ! ctx.isAfterTyper
0 commit comments