Skip to content

Commit

Permalink
Add an adaptation step in Inliner
Browse files Browse the repository at this point in the history
We sometimes face a problem that we inline a reference `x: T` which upon further inlining
is adapted to an expected type `x`. It only seems to occur in complicated scenarios. I could
not completely narrow it down. But in any case it's safe to drop the widening cast in order
to avoid a type error here. We do that in a last-effort adaptation step that's only enabled
in the Inliner: Faced with an expression `x: T` and a singleton expected type `y.type` where
`x.type <: y.type`, rewrite to `x`.
  • Loading branch information
odersky committed Oct 3, 2024
1 parent 2eb52e4 commit 0a416d8
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 1 deletion.
6 changes: 6 additions & 0 deletions compiler/src/dotty/tools/dotc/inlines/Inliner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -957,6 +957,12 @@ class Inliner(val call: tpd.Tree)(using Context):
case None => tree
case _ =>
tree

/** For inlining only: Given `(x: T)` with expected type `x.type`, replace the tree with `x`.
*/
override def healAdapt(tree: Tree, pt: Type)(using Context): Tree = (tree, pt) match
case (Typed(tree1, _), pt: SingletonType) if tree1.tpe <:< pt => tree1
case _ => tree
end InlineTyper

/** Drop any side-effect-free bindings that are unused in expansion or other reachable bindings.
Expand Down
10 changes: 9 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4602,7 +4602,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer

def recover(failure: SearchFailureType) =
if canDefineFurther(wtp) || canDefineFurther(pt) then readapt(tree)
else err.typeMismatch(tree, pt, failure)
else
val tree1 = healAdapt(tree, pt)
if tree1 ne tree then readapt(tree1)
else err.typeMismatch(tree, pt, failure)

pt match
case _: SelectionProto =>
Expand Down Expand Up @@ -4751,6 +4754,11 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
}
}

/** Hook for inheriting Typers to do a last-effort adaptation. If a different
* tree is returned, we will readpat that one, ptherwise we issue a type error afterwards.
*/
protected def healAdapt(tree: Tree, pt: Type)(using Context): Tree = tree

/** True if this inline typer has already issued errors */
def hasInliningErrors(using Context): Boolean = false

Expand Down
2 changes: 2 additions & 0 deletions tests/pos/i21413.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
val x = (aaa = 1).aaa
//val y = x.aaa

0 comments on commit 0a416d8

Please sign in to comment.