Skip to content
Draft
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
14 changes: 14 additions & 0 deletions compiler/src/dotty/tools/dotc/inlines/Inliner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,20 @@ class Inliner(val call: tpd.Tree)(using Context):
reduceInlineMatchExpr(sel)
}

private def shouldStripAscription(tree: Typed)(using Context): Boolean =
val exprTp = tree.expr.tpe
tree.hasAttachment(PrepareInlineable.InlineResultAscription)
&& enclosingInlineds.size > 1
&& exprTp.exists
&& !exprTp.widen.isRef(defn.NothingClass)
&& !exprTp.widen.isRef(defn.NullClass)
&& (exprTp frozen_<:< tree.tpe)

override def typedTyped(tree: untpd.Typed, pt: Type)(using Context): Tree =
super.typedTyped(tree, pt) match
case typedTree: Typed if shouldStripAscription(typedTree) => typedTree.expr
case typedTree => typedTree

override def newLikeThis(nestingLevel: Int): Typer = new InlineTyper(initialErrorCount, nestingLevel)

/** True if this inline typer has already issued errors */
Expand Down
12 changes: 9 additions & 3 deletions compiler/src/dotty/tools/dotc/inlines/Inlines.scala
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ object Inlines:

if tree.symbol.isConstructor then return tree // error already reported for the inline constructor definition

tree match
case Block(bindings, expr) =>
return cpy.Block(tree)(bindings, inlineCall(expr))
case _ =>
()

/** Set the position of all trees logically contained in the expansion of
* inlined call `call` to the position of `call`. This transform is necessary
* when lifting bindings from the expansion to the outside of the call.
Expand All @@ -134,9 +140,9 @@ object Inlines:
* inline call expansions smaller.
*/
def liftBindings(tree: Tree, liftPos: Tree => Tree): Tree = tree match {
case Block(stats, expr) =>
bindings ++= stats.map(liftPos)
liftBindings(expr, liftPos)
//case Block(stats, expr) =>
// bindings ++= stats.map(liftPos)
// liftBindings(expr, liftPos)
case tree @ Inlined(call, stats, expr) =>
bindings ++= stats.map(liftPos)
val lifter = liftFromInlined(call)
Expand Down
10 changes: 9 additions & 1 deletion compiler/src/dotty/tools/dotc/inlines/PrepareInlineable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ object PrepareInlineable {

private val InlineAccessorsKey = new Property.Key[InlineAccessors]

/** Indicates that an ascription was inserted by [[PrepareInlinable.wrapRHS]].
* It is used to remove it [[Inliner.stripInlineResultAscription]].
*/
val InlineResultAscription = new Property.StickyKey[Unit]

def initContext(ctx: Context): Context =
ctx.fresh.setProperty(InlineAccessorsKey, new InlineAccessors)

Expand Down Expand Up @@ -246,7 +251,10 @@ object PrepareInlineable {

/** The type ascription `rhs: tpt`, unless `original` is `transparent`. */
def wrapRHS(original: untpd.DefDef, tpt: Tree, rhs: Tree)(using Context): Tree =
if original.mods.is(Transparent) then rhs else Typed(rhs, tpt)
if original.mods.is(Transparent) then
rhs
else
Typed(rhs, tpt).withAttachment(InlineResultAscription, ())

/** Return result of evaluating `op`, but drop `Inline` flag and `Body` annotation
* of `sym` in case that leads to errors.
Expand Down
3 changes: 3 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/ReTyper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ class ReTyper(nestingLevel: Int = 0) extends Typer(nestingLevel) with ReChecking
override def typedTyped(tree: untpd.Typed, pt: Type)(using Context): Tree = {
assertTyped(tree)

if tree.hasAttachment(Typer.NoLocalRefsAscription) then
return typedExpr(tree.expr, pt)

val tpt1 = checkSimpleKinded(typedType(tree.tpt))
val expr1 = tree.expr match {
case id: untpd.Ident if (ctx.mode is Mode.Pattern) && untpd.isVarPattern(id) && (id.name == nme.WILDCARD || id.name == nme.WILDCARD_STAR) =>
Expand Down
5 changes: 4 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ object Typer {
/** Indicates that an expression is explicitly ascribed to [[Unit]] type. */
val AscribedToUnit = new Property.StickyKey[Unit]

/** Indicates that this ascription was inserted by `ensureNoLocalRefs`. */
val NoLocalRefsAscription = new Property.StickyKey[Unit]

/** Tree adaptation lost fidelity; this attachment preserves the original tree. */
val AdaptedTree = new Property.StickyKey[tpd.Tree]

Expand Down Expand Up @@ -1580,7 +1583,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
case _ =>
val target = pt.simplified
val targetTpt = TypeTree(target, inferred = true)
if tree.tpe <:< target then Typed(tree, targetTpt)
if tree.tpe <:< target then Typed(tree, targetTpt).withAttachment(NoLocalRefsAscription, ())
else
// This case should not normally arise. It currently does arise in test cases
// pos/t4080b.scala and pos/i7067.scala. In that case, a type ascription is wrong
Expand Down
9 changes: 9 additions & 0 deletions tests/neg/i18123b.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-- [E007] Type Mismatch Error: tests/neg/i18123b.scala:8:8 -------------------------------------------------------------
8 |def z = y.rep().toUpperCase // error
| ^^^^^^^
| Found: (??? : => Nothing)
| Required: ?{ toUpperCase: ? }
| Note that implicit conversions were not tried because the result of an implicit conversion
| must be more specific than ?{ toUpperCase: <?> }
|
| longer explanation available when compiling with `-explain`
8 changes: 8 additions & 0 deletions tests/neg/i18123b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Minimized version of `tests/pos/i18123.scala` to test #24425.

extension (x: String)
transparent inline def rep(min: Int = 0): String = ???

def y: String = ???

def z = y.rep().toUpperCase // error
13 changes: 13 additions & 0 deletions tests/pos/i24412.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
object test {
import scala.compiletime.erasedValue

inline def contains[T <: Tuple, E]: Boolean = inline erasedValue[T] match {
case _: EmptyTuple => false
case _: (_ *: tail) => contains[tail, E]
}
inline def check[T <: Tuple]: Unit = {
inline if contains[T, Long] && false then ???
}

check[(String, Double)]
}
12 changes: 12 additions & 0 deletions tests/run/i24420-inline-local-ref.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
inline def f(): Long =
1L

inline def g(): Long =
inline val x = f()
x

inline def h(): Long =
inline if g() > 0L then 1L else 0L

@main def Test: Unit =
assert(h() == 1L)
25 changes: 25 additions & 0 deletions tests/run/i24420-inline-val.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
inline def f1(): Long =
1L

inline def f2(): Long =
inline val x = f1() + 1L
x

inline def f3(): Long =
inline val x = f1()
x

inline def g1(): Boolean =
true

inline def g2(): Long =
inline if g1() then 1L else 2L

inline def g3(): Long =
inline if f1() > 0L then 1L else 2L

@main def Test: Unit =
assert(f2() == 2L)
assert(f3() == 1L)
assert(g2() == 1L)
assert(g3() == 1L)
12 changes: 12 additions & 0 deletions tests/run/i24420-transparent-inline-local-ref.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
transparent inline def f(): Long =
1L

transparent inline def g(): Long =
inline val x = f()
x

transparent inline def h(): Long =
inline if g() > 0L then 1L else 0L

@main def Test: Unit =
assert(h() == 1L)
Loading