Skip to content

Commit

Permalink
Merge pull request #10160 from som-snytt/issue/12645-whitebox-inference
Browse files Browse the repository at this point in the history
  • Loading branch information
SethTisue committed Sep 30, 2022
2 parents 8c6b49b + 3c7368b commit 6966b64
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 14 deletions.
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)
}
"""
}
}

0 comments on commit 6966b64

Please sign in to comment.