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

-Xsource:3 now respects refinements by whitebox macro overrides #10160

Merged
merged 1 commit into from Sep 30, 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
5 changes: 1 addition & 4 deletions src/compiler/scala/tools/nsc/typechecker/Namers.scala
Expand Up @@ -1127,7 +1127,7 @@ trait Namers extends MethodSynthesis {
case _ => defnTyper.computeType(tree.rhs, pt)
}
tree.tpt.defineType {
if (currentRun.isScala3 && !pt.isWildcard && pt != NoType && !pt.isErroneous) pt
if (currentRun.isScala3 && !pt.isWildcard && pt != NoType && !pt.isErroneous && openMacros.isEmpty) pt
else dropIllegalStarTypes(widenIfNecessary(tree.symbol, rhsTpe, pt))
}.setPos(tree.pos.focus)
tree.tpt.tpe
Expand Down Expand Up @@ -1319,7 +1319,6 @@ trait Namers extends MethodSynthesis {
val tparamSyms = typer.reenterTypeParams(tparams)
val tparamSkolems = tparams.map(_.symbol)


/*
* Creates a method type using tparamSyms and vparamsSymss as argument symbols and `respte` as result type.
* All typeRefs to type skolems are replaced by references to the corresponding non-skolem type parameter,
Expand All @@ -1331,7 +1330,6 @@ trait Namers extends MethodSynthesis {
def deskolemizedPolySig(vparamSymss: List[List[Symbol]], restpe: Type) =
GenPolyType(tparamSyms, methodTypeFor(meth, vparamSymss, restpe).substSym(tparamSkolems, tparamSyms))


if (tpt.isEmpty && meth.name == nme.CONSTRUCTOR) {
tpt defineType context.enclClass.owner.tpe_*
tpt setPos meth.pos.focus
Expand All @@ -1351,7 +1349,6 @@ trait Namers extends MethodSynthesis {
tptTyped.tpe
}


// ignore missing types unless we can look to overridden method to recover the missing information
val canOverride = methOwner.isClass && !meth.isConstructor
val inferResTp = canOverride && tpt.isEmpty
Expand Down
18 changes: 8 additions & 10 deletions src/compiler/scala/tools/nsc/typechecker/Typers.scala
Expand Up @@ -14,7 +14,7 @@ package scala
package tools.nsc
package typechecker

import scala.annotation.tailrec
import scala.annotation.{tailrec, unused}
import scala.collection.mutable
import scala.reflect.internal.{Chars, TypesStats}
import scala.reflect.internal.util.{FreshNameCreator, ListOfNil, Statistics}
Expand Down Expand Up @@ -6272,27 +6272,25 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
tpe
}

def computeMacroDefType(ddef: DefDef, pt: Type): Type = {
// called from `methodSig`. Macro defs must have an explicit type.
// The supplied expected type is ignored.
def computeMacroDefType(ddef: DefDef, @unused pt: Type): Type = {
assert(context.owner.isMacro, context.owner)
assert(ddef.symbol.isMacro, ddef.symbol)

// macro defs are typechecked in `methodSig` (by calling this method) in order to establish their link to macro implementation asap
// if a macro def doesn't have explicitly specified return type, this method will be called again by `assignTypeToTree`
// here we guard against this case
val rhs1 =
if (transformed contains ddef.rhs) {
if (transformed contains ddef.rhs)
transformed(ddef.rhs)
} else {
else {
val rhs1 = typedMacroBody(this, ddef)
transformed(ddef.rhs) = rhs1
rhs1
}

val isMacroBodyOkay = !ddef.symbol.isErroneous && !(rhs1 exists (_.isErroneous)) && rhs1 != EmptyTree
val isMacroBodyOkay = !ddef.symbol.isErroneous && !rhs1.exists(_.isErroneous) && rhs1 != EmptyTree
val shouldInheritMacroImplReturnType = ddef.tpt.isEmpty
if (isMacroBodyOkay && shouldInheritMacroImplReturnType) {
val commonMessage = "macro defs must have explicitly specified return types"
def reportFailure() = {
val commonMessage = "macro defs must have explicitly specified return types"
ddef.symbol.setFlag(IS_ERROR)
context.error(ddef.pos, commonMessage)
}
Expand Down
20 changes: 20 additions & 0 deletions test/files/pos/t12645/Macro_1.scala
@@ -0,0 +1,20 @@

// scalac: -Xsource:3

import language.experimental.macros
import scala.reflect.macros.whitebox.Context

trait Greeter {
def greeting: Option[Any] = Some("Take me to your leader, Greeter.")
}

class Welcomer {
def greeter: Greeter = macro Macros.impl
}

object Macros {
def impl(c: Context) = {
import c.universe._
q"""new Greeter { override def greeting = Some("hello, quoted world") }"""
}
}
8 changes: 8 additions & 0 deletions test/files/pos/t12645/Test_2.scala
@@ -0,0 +1,8 @@

// scalac: -Xsource:3

object Test extends App {
def f(s: String) = println(s)
val welcomer = new Welcomer
welcomer.greeter.greeting.foreach(f)
}
6 changes: 6 additions & 0 deletions test/files/pos/t12645b/Test_2.scala
@@ -0,0 +1,6 @@
// scalac: -Xsource:3

object Test extends App {
Foo.ctx.quote(42).ast.id
}
// was: Test_2.scala:4: error: value id is not a member of Ast
31 changes: 31 additions & 0 deletions test/files/pos/t12645b/macro_1.scala
@@ -0,0 +1,31 @@

// scalac: -Xsource:3

import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context

trait Ast
case class Foo(id: Int) extends Ast
object Foo {
val ctx = new Ctx {}
}

trait Ctx {
trait Quoted[+A] {
def ast: Ast
}
final def quote[A](a: A): Quoted[A] = macro QuoteMacro.quoteImpl[A]
}

class QuoteMacro(val c: Context) {
import c.universe.*

def quoteImpl[A](a: c.Expr[A])(implicit t: WeakTypeTag[A]) =
c.untypecheck {
q"""
new ${c.prefix}.Quoted[$t] {
def ast = Foo(42)
}
"""
}
}