Skip to content

Commit ddcba10

Browse files
committed
SI-5751 cleans up toolboxes for the release
Removes the `freeTypes` parameters on `typeCheckExpr` and `runExpr`, since we now have public `substituteTypes` on both trees and types. Also implements long-awaited `inferImplicitValue` and `inferImplicitView` (thanks to Miles Sabin for nudging me!)
1 parent f469387 commit ddcba10

File tree

9 files changed

+153
-113
lines changed

9 files changed

+153
-113
lines changed

src/compiler/scala/reflect/makro/runtime/Typers.scala

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ trait Typers {
1010

1111
def typeCheck(tree: Tree, pt: Type = universe.WildcardType, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): Tree = {
1212
macroLogVerbose("typechecking %s with expected type %s, implicit views = %s, macros = %s".format(tree, pt, !withImplicitViewsDisabled, !withMacrosDisabled))
13-
val wrapper1 = if (!withImplicitViewsDisabled) (callsiteTyper.context.withImplicitsEnabled[Tree] _) else (callsiteTyper.context.withImplicitsDisabled[Tree] _)
14-
val wrapper2 = if (!withMacrosDisabled) (callsiteTyper.context.withMacrosEnabled[Tree] _) else (callsiteTyper.context.withMacrosDisabled[Tree] _)
13+
val context = callsiteTyper.context
14+
val wrapper1 = if (!withImplicitViewsDisabled) (context.withImplicitsEnabled[Tree] _) else (context.withImplicitsDisabled[Tree] _)
15+
val wrapper2 = if (!withMacrosDisabled) (context.withMacrosEnabled[Tree] _) else (context.withMacrosDisabled[Tree] _)
1516
def wrapper (tree: => Tree) = wrapper1(wrapper2(tree))
1617
// if you get a "silent mode is not available past typer" here
1718
// don't rush to change the typecheck not to use the silent method when the silent parameter is false
@@ -31,29 +32,21 @@ trait Typers {
3132

3233
def inferImplicitValue(pt: Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, pos: Position = enclosingPosition): Tree = {
3334
macroLogVerbose("inferring implicit value of type %s, macros = %s".format(pt, !withMacrosDisabled))
34-
import universe.analyzer.SearchResult
35-
val context = callsiteTyper.context
36-
val wrapper1 = if (!withMacrosDisabled) (context.withMacrosEnabled[SearchResult] _) else (context.withMacrosDisabled[SearchResult] _)
37-
def wrapper (inference: => SearchResult) = wrapper1(inference)
38-
wrapper(universe.analyzer.inferImplicit(universe.EmptyTree, pt, true, false, context, !silent, pos)) match {
39-
case failure if failure.tree.isEmpty =>
40-
macroLogVerbose("implicit search has failed. to find out the reason, turn on -Xlog-implicits")
41-
if (context.hasErrors) throw new universe.TypeError(context.errBuffer.head.errPos, context.errBuffer.head.errMsg)
42-
universe.EmptyTree
43-
case success =>
44-
success.tree
45-
}
35+
inferImplicit(universe.EmptyTree, pt, isView = false, silent = silent, withMacrosDisabled = withMacrosDisabled, pos = pos)
36+
}
37+
38+
def inferImplicitView(tree: Tree, from: Type, to: Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, pos: Position = enclosingPosition): Tree = {
39+
macroLogVerbose("inferring implicit view from %s to %s for %s, macros = %s".format(from, to, tree, !withMacrosDisabled))
40+
val viewTpe = universe.appliedType(universe.definitions.FunctionClass(1).asTypeConstructor, List(from, to))
41+
inferImplicit(tree, viewTpe, isView = true, silent = silent, withMacrosDisabled = withMacrosDisabled, pos = pos)
4642
}
4743

48-
def inferImplicitView(tree: Tree, from: Type, to: Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, reportAmbiguous: Boolean = true, pos: Position = enclosingPosition): Tree = {
49-
macroLogVerbose("inferring implicit view from %s to %s for %s, macros = %s, reportAmbiguous = %s".format(from, to, tree, !withMacrosDisabled, reportAmbiguous))
44+
private def inferImplicit(tree: Tree, pt: Type, isView: Boolean, silent: Boolean, withMacrosDisabled: Boolean, pos: Position): Tree = {
5045
import universe.analyzer.SearchResult
5146
val context = callsiteTyper.context
5247
val wrapper1 = if (!withMacrosDisabled) (context.withMacrosEnabled[SearchResult] _) else (context.withMacrosDisabled[SearchResult] _)
5348
def wrapper (inference: => SearchResult) = wrapper1(inference)
54-
val fun1 = universe.definitions.FunctionClass(1)
55-
val viewTpe = universe.TypeRef(fun1.typeConstructor.prefix, fun1, List(from, to))
56-
wrapper(universe.analyzer.inferImplicit(tree, viewTpe, reportAmbiguous, true, context, !silent, pos)) match {
49+
wrapper(universe.analyzer.inferImplicit(tree, pt, reportAmbiguous = true, isView = isView, context = context, saveAmbiguousDivergent = !silent, pos = pos)) match {
5750
case failure if failure.tree.isEmpty =>
5851
macroLogVerbose("implicit search has failed. to find out the reason, turn on -Xlog-implicits")
5952
if (context.hasErrors) throw new universe.TypeError(context.errBuffer.head.errPos, context.errBuffer.head.errMsg)

src/compiler/scala/tools/reflect/ToolBox.scala

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,40 +24,46 @@ trait ToolBox[U <: Universe] {
2424
/** Typechecks a tree using this ToolBox.
2525
* This populates symbols and types of the tree and possibly transforms it to reflect certain desugarings.
2626
*
27-
* If the tree has unresolved type variables (represented as instances of ``FreeTypeSymbol'' symbols),
28-
* then they might, might be partially or might not be specified in the ``freeTypes'' parameter.
27+
* If the tree has unresolved type variables (represented as instances of `FreeTypeSymbol` symbols),
28+
* then they all have to be resolved first using `Tree.substituteTypes`, or an error occurs.
2929
*
30-
* If ``silent'' is false, ``TypeError'' will be thrown in case of a typecheck error.
31-
* If ``silent'' is true, the typecheck is silent and will return ``EmptyTree'' if an error occurs.
30+
* If `silent` is false, `TypeError` will be thrown in case of a typecheck error.
31+
* If `silent` is true, the typecheck is silent and will return `EmptyTree` if an error occurs.
3232
* Such errors don't vanish and can be inspected by turning on -Ydebug.
3333
*
3434
* Typechecking can be steered with the following optional parameters:
35-
* ``withImplicitViewsDisabled'' recursively prohibits implicit views (though, implicit vals will still be looked up and filled in), default value is false
36-
* ``withMacrosDisabled'' recursively prohibits macro expansions and macro-based implicits, default value is false
35+
* `withImplicitViewsDisabled` recursively prohibits implicit views (though, implicit vals will still be looked up and filled in), default value is false
36+
* `withMacrosDisabled` recursively prohibits macro expansions and macro-based implicits, default value is false
3737
*/
38-
def typeCheck(tree: u.Tree, pt: u.Type = u.WildcardType, freeTypes: Map[u.FreeTypeSymbol, u.Type] = Map[u.FreeTypeSymbol, u.Type](), silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): u.Tree
38+
def typeCheck(tree: u.Tree, pt: u.Type = u.WildcardType, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): u.Tree
3939

40-
41-
/** Infers an implicit value of the expected type ``pt'' in the macro callsite context.
40+
/** Infers an implicit value of the expected type `pt` in top-level context.
41+
* Optional `pos` parameter provides a position that will be associated with the implicit search.
42+
*
43+
* As mentioned in https://groups.google.com/forum/#!topic/scala-internals/ta-vbUT6JE8
44+
* this API won't take into account the lexical context of the callsite, because
45+
* currently it's impossible to reify it.
4246
*
43-
* If ``silent'' is false, ``TypeError'' will be thrown in case of an inference error.
44-
* If ``silent'' is true, the typecheck is silent and will return ``EmptyTree'' if an error occurs.
47+
* If `silent` is false, `TypeError` will be thrown in case of an inference error.
48+
* If `silent` is true, the typecheck is silent and will return `EmptyTree` if an error occurs.
4549
* Such errors don't vanish and can be inspected by turning on -Xlog-implicits.
46-
* Unlike in ``typeCheck'', ``silent'' is true by default.
50+
* Unlike in `typeCheck`, `silent` is true by default.
4751
*/
48-
def inferImplicitValue(pt: u.Type, silent: Boolean = true, withMacrosDisabled: Boolean = false): u.Tree
52+
def inferImplicitValue(pt: u.Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, pos: u.Position = u.NoPosition): u.Tree
4953

50-
/** Infers an implicit view from the provided tree ``tree'' from the type ``from'' to the type ``to'' in the macro callsite context.
54+
/** Infers an implicit view from the provided tree `tree` from the type `from` to the type `to` in the toplevel context.
55+
* Optional `pos` parameter provides a position that will be associated with the implicit search.
5156
*
52-
* Otional parameter, ``reportAmbiguous`` controls whether ambiguous implicit errors should be reported.
53-
* If we search for a view simply to find out whether one type is coercible to another, it might be desirable to set this flag to ``false''.
57+
* As mentioned in https://groups.google.com/forum/#!topic/scala-internals/ta-vbUT6JE8
58+
* this API won't take into account the lexical context of the callsite, because
59+
* currently it's impossible to reify it.
5460
*
55-
* If ``silent'' is false, ``TypeError'' will be thrown in case of an inference error.
56-
* If ``silent'' is true, the typecheck is silent and will return ``EmptyTree'' if an error occurs.
61+
* If `silent` is false, `TypeError` will be thrown in case of an inference error.
62+
* If `silent` is true, the typecheck is silent and will return `EmptyTree` if an error occurs.
5763
* Such errors don't vanish and can be inspected by turning on -Xlog-implicits.
58-
* Unlike in ``typeCheck'', ``silent'' is true by default.
64+
* Unlike in `typeCheck`, `silent` is true by default.
5965
*/
60-
def inferImplicitView(tree: u.Tree, from: u.Type, to: u.Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, reportAmbiguous: Boolean = true): u.Tree
66+
def inferImplicitView(tree: u.Tree, from: u.Type, to: u.Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, pos: u.Position = u.NoPosition): u.Tree
6167

6268
/** Recursively resets symbols and types in a given tree.
6369
*
@@ -78,14 +84,14 @@ trait ToolBox[U <: Universe] {
7884

7985
/** Compiles and runs a tree using this ToolBox.
8086
*
81-
* If the tree has unresolved type variables (represented as instances of ``FreeTypeSymbol'' symbols),
82-
* then they all have to be specified in the ``freeTypes'' parameter or an error occurs.
87+
* If the tree has unresolved type variables (represented as instances of `FreeTypeSymbol` symbols),
88+
* then they all have to be resolved first using `Tree.substituteTypes`, or an error occurs.
8389
*
8490
* This spawns the compiler at the Namer phase, and pipelines the tree through that compiler.
85-
* Currently ``runExpr'' does not accept trees that already typechecked, because typechecking isn't idempotent.
91+
* Currently `runExpr` does not accept trees that already typechecked, because typechecking isn't idempotent.
8692
* For more info, take a look at https://issues.scala-lang.org/browse/SI-5464.
8793
*/
88-
def runExpr(tree: u.Tree, freeTypes: Map[u.FreeTypeSymbol, u.Type] = Map[u.FreeTypeSymbol, u.Type]()): Any
94+
def runExpr(tree: u.Tree): Any
8995
}
9096

9197
/** Represents an error during toolboxing

0 commit comments

Comments
 (0)