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

Under -Xsource:3, adjust 2.13.9 change to ignore override type for whitebox macro expansion #10188

Merged
merged 1 commit into from Oct 26, 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
24 changes: 22 additions & 2 deletions src/compiler/scala/tools/nsc/typechecker/Namers.scala
Expand Up @@ -1120,14 +1120,34 @@ trait Namers extends MethodSynthesis {

/** Computes the type of the body in a ValDef or DefDef, and
* assigns the type to the tpt's node. Returns the type.
*
* Under `-Xsource:3`, use `pt`, the type of the overridden member.
* But preserve the precise type of a whitebox macro.
* For `def f = macro g`, here we see `def f = xp(g)` the expansion,
* not the `isMacro` case: `openMacros` will be nonEmpty.
* For `def m = f`, retrieve the typed RHS and check if it is an expansion;
* in that case, check if the expandee `f` is whitebox and preserve
* the precise type if it is. The user must provide an explicit type
* to "opt out" of the inferred narrow type; in Scala 3, they would
* inline the def to "opt in".
*/
private def assignTypeToTree(tree: ValOrDefDef, defnTyper: Typer, pt: Type): Type = {
val rhsTpe = tree match {
case ddef: DefDef if tree.symbol.isTermMacro => defnTyper.computeMacroDefType(ddef, pt)
case ddef: DefDef if tree.symbol.isTermMacro => defnTyper.computeMacroDefType(ddef, pt) // unreached, see methodSig
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this can be removed?

There's also a comment in computeMacroDefType saying

if a macro def doesn't have explicitly specified return type, this method will be called again by assignTypeToTree

is that stale?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was reluctant to expand the scope, as macros remain experimental.

case _ => defnTyper.computeType(tree.rhs, pt)
}
tree.tpt.defineType {
if (currentRun.isScala3 && !pt.isWildcard && pt != NoType && !pt.isErroneous && openMacros.isEmpty) pt
val inferOverridden = currentRun.isScala3 &&
!pt.isWildcard && pt != NoType && !pt.isErroneous &&
openMacros.isEmpty && {
context.unit.transformed.get(tree.rhs) match {
case Some(t) if t.hasAttachment[MacroExpansionAttachment] =>
val xp = macroExpandee(t)
xp.symbol == null || isBlackbox(xp.symbol)
case _ => true
}
}
if (inferOverridden) pt
else dropIllegalStarTypes(widenIfNecessary(tree.symbol, rhsTpe, pt))
}.setPos(tree.pos.focus)
tree.tpt.tpe
Expand Down
4 changes: 4 additions & 0 deletions test/files/neg/t12647.check
@@ -0,0 +1,4 @@
Test_3.scala:6: error: value value is not a member of Result
println(resolver.resolve.value)
^
1 error
13 changes: 13 additions & 0 deletions test/files/neg/t12647/Macro_1.scala
@@ -0,0 +1,13 @@

// scalac: -Xsource:3

import scala.reflect.macros.blackbox.Context

trait Result

object Macros {
def impl(c: Context) = {
import c.universe._
q"""new Result { def value = "Was this the answer you sought?" }"""
}
}
13 changes: 13 additions & 0 deletions test/files/neg/t12647/Resolve_2.scala
@@ -0,0 +1,13 @@

// scalac: -Xsource:3

import language.experimental.macros

trait Resolver {
def resolve: Result = ???
}

class ValueResolver extends Resolver {
override def resolve = valueResult
def valueResult: Result = macro Macros.impl
}
7 changes: 7 additions & 0 deletions test/files/neg/t12647/Test_3.scala
@@ -0,0 +1,7 @@

// scalac: -Xsource:3

object Test extends App {
val resolver = new ValueResolver
println(resolver.resolve.value)
}
13 changes: 13 additions & 0 deletions test/files/pos/t12647/Macro_1.scala
@@ -0,0 +1,13 @@

// scalac: -Xsource:3

import scala.reflect.macros.whitebox.Context

trait Result

object Macros {
def impl(c: Context) = {
import c.universe._
q"""new Result { def value = "Was this the answer you sought?" }"""
}
}
13 changes: 13 additions & 0 deletions test/files/pos/t12647/Resolve_2.scala
@@ -0,0 +1,13 @@

// scalac: -Xsource:3

import language.experimental.macros

trait Resolver {
def resolve: Result = ???
}

class ValueResolver extends Resolver {
override def resolve = valueResult
def valueResult: Result = macro Macros.impl
}
7 changes: 7 additions & 0 deletions test/files/pos/t12647/Test_3.scala
@@ -0,0 +1,7 @@

// scalac: -Xsource:3

object Test extends App {
val resolver = new ValueResolver
println(resolver.resolve.value)
}
11 changes: 11 additions & 0 deletions test/files/pos/t12647b/Macro_1.scala
@@ -0,0 +1,11 @@

import scala.reflect.macros.whitebox.Context

trait Result

object Macros {
def impl(c: Context): c.Tree = {
import c.universe._
q"""new Result { def value = "Was this the answer you sought?" }"""
}
}
11 changes: 11 additions & 0 deletions test/files/pos/t12647b/Resolve_2.scala
@@ -0,0 +1,11 @@

import language.experimental.macros

abstract class Resolver {
def resolve: Result = ???
}

class ValueResolver extends Resolver {
override def resolve = valueResult
def valueResult: Result = macro Macros.impl
}
5 changes: 5 additions & 0 deletions test/files/pos/t12647b/Test_3.scala
@@ -0,0 +1,5 @@

object Test extends App {
val resolver = new ValueResolver
println(resolver.resolve.value)
}