Skip to content

Commit c3f1d57

Browse files
authored
Merge pull request scala#6942 from som-snytt/issue/no-macro-inference
Enforce explicit return type for macros [ci: last-only]
2 parents c90e1f4 + f101251 commit c3f1d57

File tree

73 files changed

+299
-309
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+299
-309
lines changed

src/compiler/scala/reflect/macros/compiler/Validators.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ trait Validators {
156156
else mmap(macroDdef.vparamss)(param)
157157
val macroDefRet =
158158
if (!macroDdef.tpt.isEmpty) typer.typedType(macroDdef.tpt).tpe
159-
else computeMacroDefTypeFromMacroImplRef(macroDdef, macroImplRef) orElse AnyTpe
159+
else AnyTpe
160160
val implReturnType = sigma(increaseMetalevel(ctxPrefix, macroDefRet))
161161

162162
object SigmaTypeMap extends TypeMap {

src/compiler/scala/tools/nsc/typechecker/Macros.scala

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -323,49 +323,6 @@ trait Macros extends MacroRuntimes with Traces with Helpers {
323323
fastTrackBoxity orElse bindingBoxity getOrElse false
324324
}
325325

326-
def computeMacroDefTypeFromMacroImplRef(macroDdef: DefDef, macroImplRef: Tree): Type = {
327-
macroImplRef match {
328-
case MacroImplReference(_, _, _, macroImpl, targs) =>
329-
// Step I. Transform c.Expr[T] to T and everything else to Any
330-
var runtimeType = decreaseMetalevel(macroImpl.info.finalResultType)
331-
332-
// Step II. Transform type parameters of a macro implementation into type arguments in a macro definition's body
333-
runtimeType = runtimeType.substituteTypes(macroImpl.typeParams, targs map (_.tpe))
334-
335-
// Step III. Transform c.prefix.value.XXX to this.XXX and implParam.value.YYY to defParam.YYY
336-
def unsigma(tpe: Type): Type =
337-
transformTypeTagEvidenceParams(macroImplRef, (param, tparam) => NoSymbol) match {
338-
case (implCtxParam :: Nil) :: implParamss =>
339-
val implToDef = flatMap2(implParamss, macroDdef.vparamss)(map2(_, _)((_, _))).toMap
340-
object UnsigmaTypeMap extends TypeMap {
341-
def apply(tp: Type): Type = tp match {
342-
case TypeRef(pre, sym, args) =>
343-
val pre1 = pre match {
344-
case SingleType(SingleType(SingleType(NoPrefix, c), prefix), value) if c == implCtxParam && prefix == MacroContextPrefix && value == ExprValue =>
345-
ThisType(macroDdef.symbol.owner)
346-
case SingleType(SingleType(NoPrefix, implParam), value) if value == ExprValue =>
347-
implToDef get implParam map (defParam => SingleType(NoPrefix, defParam.symbol)) getOrElse pre
348-
case _ =>
349-
pre
350-
}
351-
val args1 = args map mapOver
352-
TypeRef(pre1, sym, args1)
353-
case _ =>
354-
mapOver(tp)
355-
}
356-
}
357-
358-
UnsigmaTypeMap(tpe)
359-
case _ =>
360-
tpe
361-
}
362-
363-
unsigma(runtimeType)
364-
case _ =>
365-
ErrorType
366-
}
367-
}
368-
369326
/** Verifies that the body of a macro def typechecks to a reference to a static public non-overloaded method or a top-level macro bundle,
370327
* and that that method is signature-wise compatible with the given macro definition.
371328
*

src/compiler/scala/tools/nsc/typechecker/Typers.scala

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5804,11 +5804,11 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
58045804
assert(context.owner.isMacro, context.owner)
58055805
assert(ddef.symbol.isMacro, ddef.symbol)
58065806

5807+
// macro defs are typechecked in `methodSig` (by calling this method) in order to establish their link to macro implementation asap
5808+
// if a macro def doesn't have explicitly specified return type, this method will be called again by `assignTypeToTree`
5809+
// here we guard against this case
58075810
val rhs1 =
58085811
if (transformed contains ddef.rhs) {
5809-
// macro defs are typechecked in `methodSig` (by calling this method) in order to establish their link to macro implementation asap
5810-
// if a macro def doesn't have explicitly specified return type, this method will be called again by `assignTypeToTree`
5811-
// here we guard against this case
58125812
transformed(ddef.rhs)
58135813
} else {
58145814
val rhs1 = typedMacroBody(this, ddef)
@@ -5824,17 +5824,9 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
58245824
ddef.symbol.setFlag(IS_ERROR)
58255825
context.error(ddef.pos, commonMessage)
58265826
}
5827-
def reportWarning(inferredType: Type) = {
5828-
val explanation = s"inference of $inferredType from macro impl's c.Expr[$inferredType] is deprecated and is going to stop working in 2.12"
5829-
context.deprecationWarning(ddef.pos, ddef.symbol, s"$commonMessage ($explanation)", "2.12.0")
5830-
}
5831-
computeMacroDefTypeFromMacroImplRef(ddef, rhs1) match {
5832-
case ErrorType => ErrorType
5833-
case NothingTpe => NothingTpe
5834-
case NoType => reportFailure(); AnyTpe
5835-
case tpe => reportWarning(tpe); tpe
5836-
}
5837-
} else AnyTpe
5827+
reportFailure()
5828+
}
5829+
AnyTpe
58385830
}
58395831

58405832
@inline final def transformedOr(tree: Tree, op: => Tree): Tree = lookupTransformed(tree) match {

test/files/neg/macro-abort/Macros_1.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ object Macros {
55
def impl(c: Context) = {
66
c.abort(c.enclosingPosition, "aborted")
77
}
8-
def abort = macro impl
9-
}
8+
def abort: Any = macro impl
9+
}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
macro-bundle-object.scala:10: error: macro implementation has incompatible shape:
2-
required: (c: scala.reflect.macros.blackbox.Context): c.Expr[Nothing]
2+
required: (c: scala.reflect.macros.blackbox.Context): c.Expr[Any]
33
or : (c: scala.reflect.macros.blackbox.Context): c.Tree
44
found : : Nothing
55
number of parameter sections differ
6-
def foo = macro Bundle.impl
7-
^
6+
def foo: Any = macro Bundle.impl
7+
^
88
one error found

test/files/neg/macro-bundle-object.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ object Bundle {
77
}
88

99
object Macros {
10-
def foo = macro Bundle.impl
11-
}
10+
def foo: Any = macro Bundle.impl
11+
}

test/files/neg/macro-exception/Macros_1.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ object Macros {
55
def impl(c: Context) = {
66
throw new Exception()
77
}
8-
def exception = macro impl
9-
}
8+
def exception: Any = macro impl
9+
}
Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,53 @@
1-
Macros_Test_2.scala:5: error: macro implementation reference has wrong shape. required:
1+
Macros_Test_2.scala:6: error: macro implementation reference has wrong shape. required:
22
macro [<static object>].<method name>[[<type args>]] or
33
macro [<macro bundle>].<method name>[[<type args>]]
4-
def foo(x: Any) = macro impls.foo
5-
^
6-
Macros_Test_2.scala:10: error: macro implementation reference has wrong shape. required:
4+
def foo(x: Any): Any = macro impls.foo
5+
^
6+
Macros_Test_2.scala:11: error: macro implementation reference has wrong shape. required:
77
macro [<static object>].<method name>[[<type args>]] or
88
macro [<macro bundle>].<method name>[[<type args>]]
9-
def foo(x: Any) = macro impls.foo
10-
^
11-
Macros_Test_2.scala:18: error: macro implementation reference has wrong shape. required:
9+
def foo(x: Any): Any = macro impls.foo
10+
^
11+
Macros_Test_2.scala:19: error: macro implementation reference has wrong shape. required:
1212
macro [<static object>].<method name>[[<type args>]] or
1313
macro [<macro bundle>].<method name>[[<type args>]]
14-
def foo(x: Any) = macro Impls3.foo
15-
^
16-
Macros_Test_2.scala:22: error: macro implementation reference has wrong shape. required:
14+
def foo(x: Any): Any = macro Impls3.foo
15+
^
16+
Macros_Test_2.scala:23: error: macro implementation reference has wrong shape. required:
1717
macro [<static object>].<method name>[[<type args>]] or
1818
macro [<macro bundle>].<method name>[[<type args>]]
19-
def foo(x: Any) = macro Impls4.foo
20-
^
21-
Macros_Test_2.scala:26: error: ambiguous reference to overloaded definition,
19+
def foo(x: Any): Any = macro Impls4.foo
20+
^
21+
Macros_Test_2.scala:27: error: ambiguous reference to overloaded definition,
2222
both method foo in object Impls5 of type (c: scala.reflect.macros.blackbox.Context)(x: c.Expr[Any], y: c.Expr[Any])Nothing
2323
and method foo in object Impls5 of type (c: scala.reflect.macros.blackbox.Context)(x: c.Expr[Any])Nothing
2424
match expected type ?
25-
def foo(x: Any) = macro Impls5.foo
26-
^
27-
Macros_Test_2.scala:27: error: ambiguous reference to overloaded definition,
25+
def foo(x: Any): Any = macro Impls5.foo
26+
^
27+
Macros_Test_2.scala:28: error: ambiguous reference to overloaded definition,
2828
both method foo in object Impls5 of type (c: scala.reflect.macros.blackbox.Context)(x: c.Expr[Any], y: c.Expr[Any])Nothing
2929
and method foo in object Impls5 of type (c: scala.reflect.macros.blackbox.Context)(x: c.Expr[Any])Nothing
3030
match expected type ?
31-
def foo(x: Any, y: Any) = macro Impls5.foo
32-
^
33-
Macros_Test_2.scala:31: error: macro implementation has incompatible shape:
34-
required: (c: scala.reflect.macros.blackbox.Context): c.Expr[Unit]
31+
def foo(x: Any, y: Any): Any = macro Impls5.foo
32+
^
33+
Macros_Test_2.scala:32: error: macro implementation has incompatible shape:
34+
required: (c: scala.reflect.macros.blackbox.Context): c.Expr[Any]
3535
or : (c: scala.reflect.macros.blackbox.Context): c.Tree
3636
found : (c: scala.reflect.macros.blackbox.Context)(): c.Expr[Unit]
3737
number of parameter sections differ
38-
def foo1 = macro Impls6.fooEmpty
39-
^
40-
Macros_Test_2.scala:32: error: macro implementation has incompatible shape:
41-
required: (c: scala.reflect.macros.blackbox.Context)(): c.Expr[Unit]
38+
def foo1: Any = macro Impls6.fooEmpty
39+
^
40+
Macros_Test_2.scala:33: error: macro implementation has incompatible shape:
41+
required: (c: scala.reflect.macros.blackbox.Context)(): c.Expr[Any]
4242
or : (c: scala.reflect.macros.blackbox.Context)(): c.Tree
4343
found : (c: scala.reflect.macros.blackbox.Context): c.Expr[Unit]
4444
number of parameter sections differ
45-
def bar1() = macro Impls6.fooNullary
46-
^
47-
Macros_Test_2.scala:36: error: type arguments [String] do not conform to method foo's type parameter bounds [U <: Int]
48-
def foo = macro Impls7.foo[String]
49-
^
50-
Macros_Test_2.scala:53: error: macro implementation must be public
51-
def foo = macro Impls8.impl
52-
^
45+
def bar1(): Any = macro Impls6.fooNullary
46+
^
47+
Macros_Test_2.scala:37: error: type arguments [String] do not conform to method foo's type parameter bounds [U <: Int]
48+
def foo: Any = macro Impls7.foo[String]
49+
^
50+
Macros_Test_2.scala:54: error: macro implementation must be public
51+
def foo: Any = macro Impls8.impl
52+
^
5353
10 errors found

test/files/neg/macro-invalidimpl.flags

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,40 @@
1+
import language.experimental.macros
12
import scala.reflect.macros.blackbox.Context
23

34
object Macros1 {
45
val impls = new Impls1
5-
def foo(x: Any) = macro impls.foo
6+
def foo(x: Any): Any = macro impls.foo
67
}
78

89
object Macros2 {
910
val impls = Impls2
10-
def foo(x: Any) = macro impls.foo
11+
def foo(x: Any): Any = macro impls.foo
1112
}
1213

1314
class Macros3 {
1415
object Impls3 {
1516
def foo(c: Context)(x: c.Expr[Any]) = ???
1617
}
1718

18-
def foo(x: Any) = macro Impls3.foo
19+
def foo(x: Any): Any = macro Impls3.foo
1920
}
2021

2122
class Macros4 extends MacroHelpers {
22-
def foo(x: Any) = macro Impls4.foo
23+
def foo(x: Any): Any = macro Impls4.foo
2324
}
2425

2526
object Macros5 {
26-
def foo(x: Any) = macro Impls5.foo
27-
def foo(x: Any, y: Any) = macro Impls5.foo
27+
def foo(x: Any): Any = macro Impls5.foo
28+
def foo(x: Any, y: Any): Any = macro Impls5.foo
2829
}
2930

3031
object Macros6 {
31-
def foo1 = macro Impls6.fooEmpty
32-
def bar1() = macro Impls6.fooNullary
32+
def foo1: Any = macro Impls6.fooEmpty
33+
def bar1(): Any = macro Impls6.fooNullary
3334
}
3435

3536
object Macros7 {
36-
def foo = macro Impls7.foo[String]
37+
def foo: Any = macro Impls7.foo[String]
3738
}
3839

3940
object Test extends App {
@@ -50,6 +51,6 @@ object Test extends App {
5051

5152
package foo {
5253
object Test extends App {
53-
def foo = macro Impls8.impl
54+
def foo: Any = macro Impls8.impl
5455
}
55-
}
56+
}

test/files/neg/macro-invalidret.check

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,57 @@
1-
Macros_Test_2.scala:2: error: macro implementation has incompatible shape:
1+
Macros_Test_2.scala:5: error: macro implementation has incompatible shape:
22
required: (c: scala.reflect.macros.blackbox.Context): c.Expr[Any]
33
or : (c: scala.reflect.macros.blackbox.Context): c.Tree
44
found : (c: scala.reflect.macros.blackbox.Context): Int
55
type mismatch for return type: Int does not conform to c.Expr[Any]
66
def foo1 = macro Impls.foo1
77
^
8-
Macros_Test_2.scala:3: error: macro implementation has incompatible shape:
8+
Macros_Test_2.scala:6: error: macro implementation has incompatible shape:
99
required: (c: scala.reflect.macros.blackbox.Context): c.Expr[Any]
1010
or : (c: scala.reflect.macros.blackbox.Context): c.Tree
1111
found : (c: scala.reflect.macros.blackbox.Context): reflect.runtime.universe.Literal
1212
type mismatch for return type: reflect.runtime.universe.Literal does not conform to c.Expr[Any]
1313
def foo2 = macro Impls.foo2
1414
^
15-
Macros_Test_2.scala:6: error: macro defs must have explicitly specified return types
15+
Macros_Test_2.scala:7: error: macro defs must have explicitly specified return types
16+
def foo3 = macro Impls.foo3
17+
^
18+
Macros_Test_2.scala:8: error: macro defs must have explicitly specified return types
19+
def foo4 = macro ???
20+
^
21+
Macros_Test_2.scala:9: error: macro defs must have explicitly specified return types
1622
def foo5 = macro Impls.foo5
1723
^
18-
Macros_Test_2.scala:7: warning: macro defs must have explicitly specified return types (inference of Int from macro impl's c.Expr[Int] is deprecated and is going to stop working in 2.12)
24+
Macros_Test_2.scala:10: error: macro defs must have explicitly specified return types
1925
def foo6 = macro Impls.foo6
2026
^
21-
Macros_Test_2.scala:14: error: exception during macro expansion:
27+
Macros_Test_2.scala:13: error: macro implementation has incompatible shape:
28+
required: (c: scala.reflect.macros.blackbox.Context): c.Expr[Int]
29+
or : (c: scala.reflect.macros.blackbox.Context): c.Tree
30+
found : (c: scala.reflect.macros.blackbox.Context): Int
31+
type mismatch for return type: Int does not conform to c.Expr[Int]
32+
def bar1: Int = macro Impls.foo1
33+
^
34+
Macros_Test_2.scala:14: error: macro implementation has incompatible shape:
35+
required: (c: scala.reflect.macros.blackbox.Context): c.Expr[Int]
36+
or : (c: scala.reflect.macros.blackbox.Context): c.Tree
37+
found : (c: scala.reflect.macros.blackbox.Context): reflect.runtime.universe.Literal
38+
type mismatch for return type: reflect.runtime.universe.Literal does not conform to c.Expr[Int]
39+
def bar2: Int = macro Impls.foo2
40+
^
41+
Macros_Test_2.scala:32: error: exception during macro expansion:
2242
java.lang.NullPointerException
2343
at Impls$.foo3(Impls_1.scala:7)
2444

25-
foo3
45+
bar3
46+
^
47+
Macros_Test_2.scala:33: error: macro implementation is missing
48+
bar4
2649
^
27-
Macros_Test_2.scala:15: error: macro implementation is missing
28-
foo4
50+
Macros_Test_2.scala:34: warning: a pure expression does nothing in statement position; multiline expressions may require enclosing parentheses
51+
bar5
2952
^
30-
Macros_Test_2.scala:17: warning: a pure expression does nothing in statement position; multiline expressions may require enclosing parentheses
31-
foo6
53+
Macros_Test_2.scala:35: warning: a pure expression does nothing in statement position; multiline expressions may require enclosing parentheses
54+
bar6
3255
^
3356
two warnings found
34-
5 errors found
57+
10 errors found

test/files/neg/macro-invalidret/Macros_Test_2.scala

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
1+
import language.experimental.macros
2+
13
object Macros {
4+
// result type required
25
def foo1 = macro Impls.foo1
36
def foo2 = macro Impls.foo2
47
def foo3 = macro Impls.foo3
58
def foo4 = macro ???
69
def foo5 = macro Impls.foo5
710
def foo6 = macro Impls.foo6
11+
12+
// various flawed attempts to implement
13+
def bar1: Int = macro Impls.foo1
14+
def bar2: Int = macro Impls.foo2
15+
def bar3: Int = macro Impls.foo3
16+
def bar4: Int = macro ???
17+
def bar5: Int = macro Impls.foo5
18+
def bar6: Int = macro Impls.foo6
819
}
920

1021
object Test extends App {
@@ -15,4 +26,11 @@ object Test extends App {
1526
foo4
1627
foo5
1728
foo6
18-
}
29+
30+
bar1
31+
bar2
32+
bar3
33+
bar4
34+
bar5
35+
bar6
36+
}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
Impls_Macros_1.scala:8: error: macro implementation has incompatible shape:
1+
Impls_Macros_1.scala:9: error: macro implementation has incompatible shape:
22
required: (c: scala.reflect.macros.blackbox.Context)(x: c.Expr[Int]): c.Expr[Nothing]
33
or : (c: scala.reflect.macros.blackbox.Context)(x: c.Tree): c.Tree
44
found : (c: scala.reflect.macros.blackbox.Context)(x: Int): Nothing
55
type mismatch for parameter x: c.Expr[Int] does not conform to Int
6-
def foo(x: Int) = macro Impls.foo
7-
^
6+
def foo(x: Int): Nothing = macro Impls.foo
7+
^
88
one error found

0 commit comments

Comments
 (0)