Skip to content

Avoid redundant type test for irrefutable @unchecked patterns #14898

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1378,7 +1378,7 @@ trait Applications extends Compatibility {
val unapplyPatterns = bunchedArgs.lazyZip(argTypes) map (typed(_, _))
val result = assignType(cpy.UnApply(tree)(unapplyFn, unapplyImplicits(unapplyApp), unapplyPatterns), ownType)
unapp.println(s"unapply patterns = $unapplyPatterns")
if ((ownType eq selType) || ownType.isError) result
if (ownType.stripped eq selType.stripped) || ownType.isError then result
else tryWithTypeTest(Typed(result, TypeTree(ownType)), selType)
case tp =>
val unapplyErr = if (tp.isError) unapplyFn else notAnExtractor(unapplyFn)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1599,7 +1599,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
result match {
case result @ Match(sel, CaseDef(pat, _, _) :: _) =>
tree.selector.removeAttachment(desugar.CheckIrrefutable) match {
case Some(checkMode) =>
case Some(checkMode) if !sel.tpe.hasAnnotation(defn.UncheckedAnnot) =>
val isPatDef = checkMode == desugar.MatchCheck.IrrefutablePatDef
if (!checkIrrefutable(sel, pat, isPatDef) && sourceVersion == `future-migration`)
if (isPatDef) patch(Span(tree.selector.span.end), ": @unchecked")
Expand Down
29 changes: 29 additions & 0 deletions tests/pos/i14821.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
trait Statement
trait Definition extends Statement

trait ClassDef extends Definition:
def constructor: DefDef

object ClassDef:
def copy(constr: DefDef): ClassDef = ???

// >>> This abstract implementation of DefDef causes a compilation error in transform...
type DefDef <: Definition
val DefDef: DefDefModule = ???
trait DefDefModule:
def unapply(ddef: DefDef): (String, List[AnyRef])
// ...unless this given TypeTest is commented out, in which case we get only a type test warning
given scala.reflect.TypeTest[Statement, DefDef] = ???

// >>> This alternative works
// trait DefDef extends Definition
// object DefDef:
// def unapply(ddef: DefDef): (String, List[AnyRef]) = ???

// >>> This alternative also works
// case class DefDef(name: String, paramss: List[AnyRef]) extends Definition

def transform(tree: Statement): Statement = tree match
case tree: ClassDef =>
val constructor @ DefDef(_, _) = transform(tree.constructor): @unchecked
ClassDef.copy(constructor)
2 changes: 2 additions & 0 deletions tests/pos/i14896.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
object Ex { def unapply(p: Any): Option[_ <: Int] = null }
object Foo { val Ex(_) = null: @unchecked }
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,16 @@ object RegressionTestScala3 {
def bar(x: Long = 0): Foo = new Foo(x)
}
}

object Issue14896 {
val obj = new js.Object {
val a = 42
val b = "foo"
}

val entries = js.Object.entries(obj)
val js.Tuple2(k, v) = entries(0): @unchecked
}
}

// This class needs to be at the top-level, not in an object, to reproduce the issue
Expand Down