Skip to content
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

Handle situation where an inline info cannot be computed #14827

Merged
merged 2 commits into from
Apr 5, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 9 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Inliner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ object Inliner {

private type DefBuffer = mutable.ListBuffer[ValOrDefDef]

/** An exception signalling that an inline info cannot be computed due to a
* cyclic reference. i14772.scala shows a case where this happens.
*/
private[typer] class MissingInlineInfo extends Exception

/** `sym` is an inline method with a known body to inline.
*/
def hasBodyToInline(sym: SymDenotation)(using Context): Boolean =
Expand Down Expand Up @@ -154,7 +159,10 @@ object Inliner {
if bindings.nonEmpty then
cpy.Block(tree)(bindings.toList, inlineCall(tree1))
else if enclosingInlineds.length < ctx.settings.XmaxInlines.value && !reachedInlinedTreesLimit then
val body = bodyToInline(tree.symbol) // can typecheck the tree and thereby produce errors
val body =
try bodyToInline(tree.symbol) // can typecheck the tree and thereby produce errors
catch case _: MissingInlineInfo =>
throw CyclicReference(ctx.owner)
new Inliner(tree, body).inlined(tree.srcPos)
else
ctx.base.stopInlining = true
Expand Down
8 changes: 8 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ class Namer { typer: Typer =>
}
}

def hasDefinedSymbol(tree: Tree)(using Context): Boolean =
val xtree = expanded(tree)
xtree.hasAttachment(TypedAhead) || xtree.hasAttachment(SymOfTree)

/** The enclosing class with given name; error if none exists */
def enclosingClassNamed(name: TypeName, span: Span)(using Context): Symbol =
if (name.isEmpty) NoSymbol
Expand Down Expand Up @@ -837,6 +841,10 @@ class Namer { typer: Typer =>
private def addInlineInfo(sym: Symbol) = original match {
case original: untpd.DefDef if sym.isInlineMethod =>
def rhsToInline(using Context): tpd.Tree =
if !original.symbol.exists && !hasDefinedSymbol(original) then
throw
if sym.isCompleted then Inliner.MissingInlineInfo()
else CyclicReference(sym)
val mdef = typedAheadExpr(original).asInstanceOf[tpd.DefDef]
PrepareInlineable.wrapRHS(original, mdef.tpt, mdef.rhs)
PrepareInlineable.registerInlineInfo(sym, rhsToInline)(using localContext(sym))
Expand Down
15 changes: 15 additions & 0 deletions tests/neg/i14772.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
-- [E044] Cyclic Error: tests/neg/i14772.scala:7:7 ---------------------------------------------------------------------
7 | foo(a) // error
| ^
| Overloaded or recursive method impl needs return type
|
| longer explanation available when compiling with `-explain`
-- Error: tests/neg/i14772.scala:8:12 ----------------------------------------------------------------------------------
8 | Expr(()) // error
| ^
| no given instance of type quoted.ToExpr[Unit] was found for parameter x$2 of method apply in object Expr.
| I found:
|
| quoted.ToExpr.ClassToExpr[T]
|
| But given instance ClassToExpr in object ToExpr does not match type quoted.ToExpr[Unit].
10 changes: 10 additions & 0 deletions tests/neg/i14772.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import scala.quoted.*

object A {
transparent inline def foo(a: Any): Any = ${ impl('a) }

def impl(a: Expr[Any])(using Quotes)/*: Expr[Any]*/ = {
foo(a) // error
Expr(()) // error
}
}