aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/dotc/ast/Desugar.scala36
-rw-r--r--src/dotty/tools/dotc/core/Contexts.scala21
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala38
-rw-r--r--src/dotty/tools/dotc/core/TyperState.scala11
-rw-r--r--src/dotty/tools/dotc/core/Types.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala55
-rw-r--r--src/dotty/tools/dotc/typer/ConstFold.scala183
-rw-r--r--src/dotty/tools/dotc/typer/Implicits.scala7
-rw-r--r--src/dotty/tools/dotc/typer/ImportInfo.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Mode.scala25
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala30
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala217
12 files changed, 506 insertions, 121 deletions
diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala
index ae1a06a74..2535e32ad 100644
--- a/src/dotty/tools/dotc/ast/Desugar.scala
+++ b/src/dotty/tools/dotc/ast/Desugar.scala
@@ -171,11 +171,13 @@ object desugar {
def anyRef = ref(defn.AnyRefAlias.typeConstructor)
- def companionDefs(parent: Tree, defs: List[Tree]) =
+ def companionDefs(parentTpt: Tree, defs: List[Tree]) = {
+ val parentConstr = Select(New(parentTpt), nme.CONSTRUCTOR)
moduleDef(
ModuleDef(
Modifiers(Synthetic), name.toTermName,
- Template(emptyConstructor, parent :: Nil, EmptyValDef(), defs))).toList
+ Template(emptyConstructor, parentConstr :: Nil, EmptyValDef(), defs))).toList
+ }
val companions =
if (mods is Case) {
@@ -234,7 +236,7 @@ object desugar {
case tree: ModuleDef => moduleDef(tree)
}
- def apply(tree: Tree, mode: Mode)(implicit ctx: Context): Tree = {
+ def apply(tree: Tree)(implicit ctx: Context): Tree = {
def labelDefAndCall(lname: TermName, rhs: Tree, call: Tree) = {
val ldef = DefDef(Modifiers(Label), lname, Nil, ListOfNil, TypeTree(), rhs)
@@ -457,8 +459,8 @@ object desugar {
}
}
- def isPatternVar(id: Ident) =
- (mode is Mode.Pattern) && isVarPattern(id) && id.name != nme.WILDCARD
+ def isPatternVar(id: Ident) = // todo: what about variables in types in patterns?
+ (ctx.mode is Mode.Pattern) && isVarPattern(id) && id.name != nme.WILDCARD
// begin desugar
val tree1 = tree match { // todo: move general tree desugaring to typer, and keep only untyped trees here?
@@ -483,31 +485,29 @@ object desugar {
case InterpolatedString(id, strs, elems) =>
Apply(Select(Apply(Ident(nme.StringContext), strs), id), elems)
case Function(args, body) =>
- if (mode is Mode.Type) // FunctionN[args: _*, body]
+ if (ctx.mode is Mode.Type) // FunctionN[args: _*, body]
AppliedTypeTree(
ref(defn.FunctionClass(args.length).typeConstructor),
args :+ body)
else
makeClosure(args.asInstanceOf[List[ValDef]], body)
case InfixOp(l, op, r) =>
- mode match {
- case Mode.Expr => // l.op(r), or val x = r; l.op(x), plus handle named args specially
- makeBinop(l, op, r)
- case Mode.Pattern => // op(l, r)
- Apply(Ident(op), l :: r :: Nil)
- case Mode.Type => // op[l, r]
- AppliedTypeTree(Ident(op), l :: r :: Nil)
- }
+ if (ctx.mode is Mode.Type)
+ AppliedTypeTree(Ident(op), l :: r :: Nil) // op[l, r]
+ else if (ctx.mode is Mode.Pattern)
+ Apply(Ident(op), l :: r :: Nil) // op(l, r)
+ else // l.op(r), or val x = r; l.op(x), plus handle named args specially
+ makeBinop(l, op, r)
case PostfixOp(t, op) =>
- if ((mode is Mode.Type) && op == nme.raw.STAR)
+ if ((ctx.mode is Mode.Type) && op == nme.raw.STAR)
AppliedTypeTree(ref(defn.RepeatedParamType), t)
else {
- assert(mode is Mode.Expr)
+ assert(ctx.mode.isExpr, ctx.mode)
if (op == nme.WILDCARD) tree // desugar later by eta expansion
else Select(t, op)
}
case PrefixOp(op, t) =>
- if ((mode is Mode.Type) && op == nme.ARROWkw)
+ if ((ctx.mode is Mode.Type) && op == nme.ARROWkw)
AppliedTypeTree(ref(defn.ByNameParamClass.typeConstructor), t)
else
Select(t, nme.UNARY_PREFIX ++ op)
@@ -516,7 +516,7 @@ object desugar {
case Tuple(ts) =>
def PairTypeTree(l: Tree, r: Tree) =
AppliedTypeTree(ref(defn.PairClass.typeConstructor), l :: r :: Nil)
- if (mode is Mode.Type) ts.reduceRight(PairTypeTree)
+ if (ctx.mode is Mode.Type) ts.reduceRight(PairTypeTree)
else if (ts.isEmpty) unitLiteral
else ts.reduceRight(Pair(_, _))
case WhileDo(cond, body) =>
diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala
index f7adbc184..ee67ec76e 100644
--- a/src/dotty/tools/dotc/core/Contexts.scala
+++ b/src/dotty/tools/dotc/core/Contexts.scala
@@ -79,12 +79,9 @@ object Contexts {
def period: Period = _period
/** The scope nesting level */
- private[this] var _scopeNestingLevel: Int = 0
- def scopeNestingLevel: Int = {
- if (this._scopeNestingLevel == outer.scopeNestingLevel && this.scope != outer.scope)
- this._scopeNestingLevel = outer.scopeNestingLevel + 1
- this._scopeNestingLevel
- }
+ private[this] var _mode: Mode = _
+ protected def mode_=(mode: Mode) = _mode = mode
+ def mode: Mode = _mode
/** The current type comparer */
private[this] var _typerState: TyperState = _
@@ -249,6 +246,7 @@ object Contexts {
if (_condensed eq outer.condensed)
_condensed = base.initialCtx.fresh
.withPeriod(period)
+ .withMode(mode)
// typerState and its constraint is not preserved in condensed
// reporter is always ThrowingReporter
.withPlainPrinter(plainPrinter)
@@ -272,6 +270,13 @@ object Contexts {
newctx.setCreationTrace()
newctx
}
+
+ def withMode(mode: Mode): Context =
+ if (mode != this.mode) fresh.withMode(mode) else this
+
+ def addMode(mode: Mode): Context = withMode(this.mode | mode)
+ def maskMode(mode: Mode): Context = withMode(this.mode & mode)
+ def retractMode(mode: Mode): Context = withMode(this.mode &~ mode)
}
/** A condensed context provides only a small memory footprint over
@@ -287,6 +292,7 @@ object Contexts {
*/
abstract class FreshContext extends CondensedContext {
def withPeriod(period: Period): this.type = { this.period = period; this }
+ override def withMode(mode: Mode): this.type = { this.mode = mode; this }
def withTyperState(typerState: TyperState): this.type = { this.typerState = typerState; this }
def withNewTyperState: this.type = withTyperState(typerState.fresh)
def withPosition(position: Position): this.type = { this.position = position; this }
@@ -311,8 +317,6 @@ object Contexts {
withSettings(setting.updateIn(sstate, value))
def withDebug = withSetting(base.settings.debug, true)
- def withImplicitsDisabled: this.type = ???
- def silent: this.type = ???
}
/** A class defining the initial context with given context base
@@ -321,6 +325,7 @@ object Contexts {
private class InitialContext(val base: ContextBase, settings: SettingGroup) extends FreshContext {
outer = NoContext
period = InitialPeriod
+ mode = Mode.None
typerState = new TyperState(new ConsoleReporter()(this))
position = NoPosition
plainPrinter = new PlainPrinter(_)
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index 66ed61a7f..757240c43 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -152,15 +152,15 @@ class Definitions(implicit ctx: Context) {
lazy val ArrayClass: ClassSymbol = requiredClass("scala.Array")
lazy val uncheckedStableClass: ClassSymbol = requiredClass("scala.annotation.unchecked.uncheckedStable")
- lazy val UnitClass = valueClassSymbol("scala.Unit", BoxedUnitClass, java.lang.Void.TYPE)
- lazy val BooleanClass = valueClassSymbol("scala.Boolean", BoxedBooleanClass, java.lang.Boolean.TYPE)
- lazy val ByteClass = valueClassSymbol("scala.Byte", BoxedByteClass, java.lang.Byte.TYPE)
- lazy val ShortClass = valueClassSymbol("scala.Short", BoxedShortClass, java.lang.Short.TYPE)
- lazy val CharClass = valueClassSymbol("scala.Char", BoxedCharClass, java.lang.Character.TYPE)
- lazy val IntClass = valueClassSymbol("scala.Int", BoxedIntClass, java.lang.Integer.TYPE)
- lazy val LongClass = valueClassSymbol("scala.Long", BoxedLongClass, java.lang.Long.TYPE)
- lazy val FloatClass = valueClassSymbol("scala.Float", BoxedFloatClass, java.lang.Float.TYPE)
- lazy val DoubleClass = valueClassSymbol("scala.Double", BoxedDoubleClass, java.lang.Double.TYPE)
+ lazy val UnitClass = valueClassSymbol("scala.Unit", BoxedUnitClass, java.lang.Void.TYPE, UnitEnc)
+ lazy val BooleanClass = valueClassSymbol("scala.Boolean", BoxedBooleanClass, java.lang.Boolean.TYPE, BooleanEnc)
+ lazy val ByteClass = valueClassSymbol("scala.Byte", BoxedByteClass, java.lang.Byte.TYPE, ByteEnc)
+ lazy val ShortClass = valueClassSymbol("scala.Short", BoxedShortClass, java.lang.Short.TYPE, ShortEnc)
+ lazy val CharClass = valueClassSymbol("scala.Char", BoxedCharClass, java.lang.Character.TYPE, CharEnc)
+ lazy val IntClass = valueClassSymbol("scala.Int", BoxedIntClass, java.lang.Integer.TYPE, IntEnc)
+ lazy val LongClass = valueClassSymbol("scala.Long", BoxedLongClass, java.lang.Long.TYPE, LongEnc)
+ lazy val FloatClass = valueClassSymbol("scala.Float", BoxedFloatClass, java.lang.Float.TYPE, FloatEnc)
+ lazy val DoubleClass = valueClassSymbol("scala.Double", BoxedDoubleClass, java.lang.Double.TYPE, DoubleEnc)
lazy val BoxedUnitClass = requiredClass("scala.runtime.BoxedUnit")
lazy val BoxedBooleanClass = requiredClass("java.lang.Boolean")
@@ -276,6 +276,8 @@ class Definitions(implicit ctx: Context) {
}
}
+ def isFunctionType(tp: Type) = FunctionClasses contains tp.typeSymbol
+
// ----- Symbol sets ---------------------------------------------------
lazy val FunctionClass = mkArityArray("Function", MaxFunctionArity, 0)
@@ -377,18 +379,21 @@ class Definitions(implicit ctx: Context) {
private[this] val _javaTypeToValueClass = mutable.Map[Class[_], Symbol]()
private[this] val _valueClassToJavaType = mutable.Map[Symbol, Class[_]]()
+ private[this] val _valueClassEnc = mutable.Map[Symbol, Int]()
val boxedClass: collection.Map[Symbol, Symbol] = _boxedClass
val unboxedClass: collection.Map[Symbol, Symbol] = _boxedClass
val javaTypeToValueClass: collection.Map[Class[_], Symbol] = _javaTypeToValueClass
val valueClassToJavaType: collection.Map[Symbol, Class[_]] = _valueClassToJavaType
+ val valueClassEnc: collection.Map[Symbol, Int] = _valueClassEnc
- private def valueClassSymbol(name: String, boxed: ClassSymbol, jtype: Class[_]): ClassSymbol = {
+ private def valueClassSymbol(name: String, boxed: ClassSymbol, jtype: Class[_], enc: Int): ClassSymbol = {
val vcls = requiredClass(name)
_unboxedClass(boxed) = vcls
_boxedClass(vcls) = boxed
_javaTypeToValueClass(jtype) = vcls
_valueClassToJavaType(vcls) = jtype
+ _valueClassEnc(vcls) = enc
vcls
}
@@ -399,6 +404,19 @@ class Definitions(implicit ctx: Context) {
else nme.genericWrapArray
}
+ val ByteEnc = 2
+ val ShortEnc = ByteEnc * 3
+ val CharEnc = 5
+ val IntEnc = ShortEnc * CharEnc
+ val LongEnc = IntEnc * 7
+ val FloatEnc = LongEnc * 11
+ val DoubleEnc = FloatEnc * 13
+ val BooleanEnc = 17
+ val UnitEnc = 19
+
+ def isValueSubClass(cls1: Symbol, cls2: Symbol) =
+ valueClassEnc(cls2) % valueClassEnc(cls1) == 0
+
// ----- Initialization ---------------------------------------------------
/** Lists core classes that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */
diff --git a/src/dotty/tools/dotc/core/TyperState.scala b/src/dotty/tools/dotc/core/TyperState.scala
index 6bf2378ba..e492eee60 100644
--- a/src/dotty/tools/dotc/core/TyperState.scala
+++ b/src/dotty/tools/dotc/core/TyperState.scala
@@ -22,8 +22,6 @@ class TyperState(val reporter: Reporter = ThrowingReporter) extends DotClass {
def fresh: TyperState = this
def commit()(implicit ctx: Context): Unit = unsupported("commit")
-
- def copyFrom(tp: TyperState): Unit = unsupported("copyFrom")
}
class MutableTyperState(previous: TyperState, reporter: Reporter)
@@ -41,13 +39,8 @@ extends TyperState(reporter) {
override def fresh: TyperState = new MutableTyperState(this, new StoreReporter)
override def commit()(implicit ctx: Context) = {
- ctx.typerState.copyFrom(this)
+ ctx.typerState.constraint = constraint
+ ctx.typerState.undetVars = undetVars
reporter.flush()
}
-
- override def copyFrom(state: TyperState): Unit = {
- constraint = state.constraint
- undetVars = state.undetVars
- }
-
}
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index f2b86242d..ef06c37f7 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -510,6 +510,8 @@ object Types {
* <o.x.type>.widen = o.C
*/
final def widen(implicit ctx: Context): Type = this match {
+ case tp: TermRef =>
+ if (tp.denot.isOverloaded) tp else tp.underlying.widen
case tp: SingletonType => tp.underlying.widen
case tp: TypeBounds => tp.hi.widen // needed?
case tp: ExprType => tp.resultType.widen
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index 210314cd4..cb397a692 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -6,6 +6,7 @@ import core._
import ast.{Trees, untpd, tpd, TreeInfo}
import util.Positions._
import Trees.Untyped
+import Mode.ImplicitsDisabled
import Contexts._
import Types._
import Flags._
@@ -44,29 +45,25 @@ object Applications {
)
}
- /** A trait defining a `normalize` method. */
- trait Normalizing {
-
- /** The normalized form of a type
- * - unwraps polymorphic types, tracking their parameters in the current constraint
- * - skips implicit parameters
- * - converts non-dependent method types to the corresponding function types
- * - dereferences parameterless method types
- */
- def normalize(tp: Type)(implicit ctx: Context): Type = tp.widen match {
- case pt: PolyType => normalize(ctx.track(pt).resultType)
- case mt: MethodType if !mt.isDependent =>
- if (mt.isImplicit) mt.resultType
- else defn.FunctionType(mt.paramTypes, mt.resultType)
- case et: ExprType => et.resultType
- case _ => tp
- }
+ /** The normalized form of a type
+ * - unwraps polymorphic types, tracking their parameters in the current constraint
+ * - skips implicit parameters
+ * - converts non-dependent method types to the corresponding function types
+ * - dereferences parameterless method types
+ */
+ def normalize(tp: Type)(implicit ctx: Context): Type = tp.widen match {
+ case pt: PolyType => normalize(ctx.track(pt).resultType)
+ case mt: MethodType if !mt.isDependent =>
+ if (mt.isImplicit) mt.resultType
+ else defn.FunctionType(mt.paramTypes, mt.resultType)
+ case et: ExprType => et.resultType
+ case _ => tp
}
}
import Applications._
-trait Applications extends Compatibility with Normalizing { self: Typer =>
+trait Applications extends Compatibility{ self: Typer =>
import Applications._
import Trees._
@@ -164,7 +161,7 @@ trait Applications extends Compatibility with Normalizing { self: Typer =>
*/
val methType = funType.widen match {
case funType: MethodType => funType
- case funType: PolyType => polyResult(ctx.track(funType))
+ case funType: PolyType => ctx.track(funType).resultType
case _ => funType
}
@@ -197,9 +194,6 @@ trait Applications extends Compatibility with Normalizing { self: Typer =>
protected def methodType = methType.asInstanceOf[MethodType]
private def methString: String = s"method ${methRef.name}: ${methType.show}"
- /** The result type of a polytype; overridden in TypedApplication */
- protected def polyResult(polytpe: PolyType): Type = polytpe.resultType
-
/** Re-order arguments to correctly align named arguments */
def reorder[T >: Untyped](args: List[Tree[T]]): List[Tree[T]] = {
var namedToArg: Map[Name, Tree[T]] =
@@ -426,7 +420,7 @@ trait Applications extends Compatibility with Normalizing { self: Typer =>
private var myNormalizedFun: tpd.Tree = fun
def addArg(arg: tpd.Tree, formal: Type): Unit =
- typedArgBuf += adapt(arg, Mode.Expr, formal)
+ typedArgBuf += adapt(arg, formal)
def makeVarArg(n: Int, elemFormal: Type): Unit = {
val args = typedArgBuf.takeRight(n).toList
@@ -452,15 +446,6 @@ trait Applications extends Compatibility with Normalizing { self: Typer =>
myNormalizedFun = liftApp(liftedDefs, myNormalizedFun)
}
- /** Replace all parameters of tracked polytype by fresh type vars,
- * and make function a TypeApply node with these type vars as arguments.
- */
- override def polyResult(poly: PolyType): Type = {
- val tvars = ctx.newTypeVars(poly)
- myNormalizedFun = tpd.TypeApply(normalizedFun, tvars map (tpd.TypeTree(_)))
- poly.substParams(poly, tvars)
- }
-
/** The index of the first difference between lists of trees `xs` and `ys`,
* where `EmptyTree`s in the second list are skipped.
* -1 if there are no differences.
@@ -505,7 +490,7 @@ trait Applications extends Compatibility with Normalizing { self: Typer =>
/** Subclass of Application for type checking an Apply node with untyped arguments. */
class ApplyToUntyped(app: untpd.Apply, fun: tpd.Tree, methRef: TermRef, args: List[untpd.Tree], resultType: Type)(implicit ctx: Context)
extends TypedApply(app, fun, methRef, args, resultType) {
- def typedArg(arg: untpd.Tree, formal: Type): TypedArg = typed(arg, Mode.Expr, formal)
+ def typedArg(arg: untpd.Tree, formal: Type): TypedArg = typed(arg, formal)
def treeToArg(arg: tpd.Tree): untpd.Tree = untpd.TypedSplice(arg)
}
@@ -683,10 +668,10 @@ trait Applications extends Compatibility with Normalizing { self: Typer =>
narrowByTypes(alts, args, resultType)
case tp =>
- alts filter (testCompatible(_, tp))
+ alts filter (alt => testCompatible(normalize(alt), tp))
}
if (isDetermined(candidates)) candidates
- else narrowMostSpecific(candidates)(ctx.fresh.withImplicitsDisabled)
+ else narrowMostSpecific(candidates)(ctx.addMode(ImplicitsDisabled))
}
} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/typer/ConstFold.scala b/src/dotty/tools/dotc/typer/ConstFold.scala
new file mode 100644
index 000000000..a66e8a9c8
--- /dev/null
+++ b/src/dotty/tools/dotc/typer/ConstFold.scala
@@ -0,0 +1,183 @@
+package dotty.tools.dotc
+package typer
+
+import java.lang.ArithmeticException
+
+import ast._
+import Trees._
+import core._
+import Types._
+import Constants._
+import Names._
+import StdNames._
+import Contexts._
+
+object ConstFold {
+
+ import tpd._
+
+ /** If tree is a constant operation, replace with result. */
+ def apply(tree: Tree)(implicit ctx: Context): Tree =
+ finish(tree) {
+ tree match {
+ case Apply(Select(xt, op), yt :: Nil) =>
+ xt.tpe match {
+ case ConstantType(x) =>
+ yt.tpe match {
+ case ConstantType(y) => foldBinop(op, x, y)
+ case _ => null
+ }
+ case _ => null
+ }
+ case Select(xt, op) =>
+ xt.tpe match {
+ case ConstantType(x) => foldUnop(op, x)
+ case _ => null
+ }
+ case _ => null
+ }
+ }
+
+ /** If tree is a constant value that can be converted to type `pt`, perform
+ * the conversion.
+ */
+ def apply(tree: Tree, pt: Type)(implicit ctx: Context): Tree =
+ finish(apply(tree)) {
+ tree.tpe match {
+ case ConstantType(x) => x convertTo pt
+ case _ => null
+ }
+ }
+
+ private def finish(tree: Tree)(compX: => Constant)(implicit ctx: Context): Tree =
+ try {
+ val x = compX
+ if (x ne null) tree withType ConstantType(x)
+ else EmptyTree
+ } catch {
+ case _: ArithmeticException => tree // the code will crash at runtime,
+ // but that is better than the
+ // compiler itself crashing
+ }
+
+ private def foldUnop(op: Name, x: Constant): Constant = (op, x.tag) match {
+ case (nme.UNARY_!, BooleanTag) => Constant(!x.booleanValue)
+
+ case (nme.UNARY_~ , IntTag ) => Constant(~x.intValue)
+ case (nme.UNARY_~ , LongTag ) => Constant(~x.longValue)
+
+ case (nme.UNARY_+ , IntTag ) => Constant(+x.intValue)
+ case (nme.UNARY_+ , LongTag ) => Constant(+x.longValue)
+ case (nme.UNARY_+ , FloatTag ) => Constant(+x.floatValue)
+ case (nme.UNARY_+ , DoubleTag ) => Constant(+x.doubleValue)
+
+ case (nme.UNARY_- , IntTag ) => Constant(-x.intValue)
+ case (nme.UNARY_- , LongTag ) => Constant(-x.longValue)
+ case (nme.UNARY_- , FloatTag ) => Constant(-x.floatValue)
+ case (nme.UNARY_- , DoubleTag ) => Constant(-x.doubleValue)
+
+ case _ => null
+ }
+
+ /** These are local helpers to keep foldBinop from overly taxing the
+ * optimizer.
+ */
+ private def foldBooleanOp(op: Name, x: Constant, y: Constant): Constant = op match {
+ case nme.ZOR => Constant(x.booleanValue | y.booleanValue)
+ case nme.OR => Constant(x.booleanValue | y.booleanValue)
+ case nme.XOR => Constant(x.booleanValue ^ y.booleanValue)
+ case nme.ZAND => Constant(x.booleanValue & y.booleanValue)
+ case nme.AND => Constant(x.booleanValue & y.booleanValue)
+ case nme.EQ => Constant(x.booleanValue == y.booleanValue)
+ case nme.NE => Constant(x.booleanValue != y.booleanValue)
+ case _ => null
+ }
+ private def foldSubrangeOp(op: Name, x: Constant, y: Constant): Constant = op match {
+ case nme.OR => Constant(x.intValue | y.intValue)
+ case nme.XOR => Constant(x.intValue ^ y.intValue)
+ case nme.AND => Constant(x.intValue & y.intValue)
+ case nme.LSL => Constant(x.intValue << y.intValue)
+ case nme.LSR => Constant(x.intValue >>> y.intValue)
+ case nme.ASR => Constant(x.intValue >> y.intValue)
+ case nme.EQ => Constant(x.intValue == y.intValue)
+ case nme.NE => Constant(x.intValue != y.intValue)
+ case nme.LT => Constant(x.intValue < y.intValue)
+ case nme.GT => Constant(x.intValue > y.intValue)
+ case nme.LE => Constant(x.intValue <= y.intValue)
+ case nme.GE => Constant(x.intValue >= y.intValue)
+ case nme.ADD => Constant(x.intValue + y.intValue)
+ case nme.SUB => Constant(x.intValue - y.intValue)
+ case nme.MUL => Constant(x.intValue * y.intValue)
+ case nme.DIV => Constant(x.intValue / y.intValue)
+ case nme.MOD => Constant(x.intValue % y.intValue)
+ case _ => null
+ }
+ private def foldLongOp(op: Name, x: Constant, y: Constant): Constant = op match {
+ case nme.OR => Constant(x.longValue | y.longValue)
+ case nme.XOR => Constant(x.longValue ^ y.longValue)
+ case nme.AND => Constant(x.longValue & y.longValue)
+ case nme.LSL => Constant(x.longValue << y.longValue)
+ case nme.LSR => Constant(x.longValue >>> y.longValue)
+ case nme.ASR => Constant(x.longValue >> y.longValue)
+ case nme.EQ => Constant(x.longValue == y.longValue)
+ case nme.NE => Constant(x.longValue != y.longValue)
+ case nme.LT => Constant(x.longValue < y.longValue)
+ case nme.GT => Constant(x.longValue > y.longValue)
+ case nme.LE => Constant(x.longValue <= y.longValue)
+ case nme.GE => Constant(x.longValue >= y.longValue)
+ case nme.ADD => Constant(x.longValue + y.longValue)
+ case nme.SUB => Constant(x.longValue - y.longValue)
+ case nme.MUL => Constant(x.longValue * y.longValue)
+ case nme.DIV => Constant(x.longValue / y.longValue)
+ case nme.MOD => Constant(x.longValue % y.longValue)
+ case _ => null
+ }
+ private def foldFloatOp(op: Name, x: Constant, y: Constant): Constant = op match {
+ case nme.EQ => Constant(x.floatValue == y.floatValue)
+ case nme.NE => Constant(x.floatValue != y.floatValue)
+ case nme.LT => Constant(x.floatValue < y.floatValue)
+ case nme.GT => Constant(x.floatValue > y.floatValue)
+ case nme.LE => Constant(x.floatValue <= y.floatValue)
+ case nme.GE => Constant(x.floatValue >= y.floatValue)
+ case nme.ADD => Constant(x.floatValue + y.floatValue)
+ case nme.SUB => Constant(x.floatValue - y.floatValue)
+ case nme.MUL => Constant(x.floatValue * y.floatValue)
+ case nme.DIV => Constant(x.floatValue / y.floatValue)
+ case nme.MOD => Constant(x.floatValue % y.floatValue)
+ case _ => null
+ }
+ private def foldDoubleOp(op: Name, x: Constant, y: Constant): Constant = op match {
+ case nme.EQ => Constant(x.doubleValue == y.doubleValue)
+ case nme.NE => Constant(x.doubleValue != y.doubleValue)
+ case nme.LT => Constant(x.doubleValue < y.doubleValue)
+ case nme.GT => Constant(x.doubleValue > y.doubleValue)
+ case nme.LE => Constant(x.doubleValue <= y.doubleValue)
+ case nme.GE => Constant(x.doubleValue >= y.doubleValue)
+ case nme.ADD => Constant(x.doubleValue + y.doubleValue)
+ case nme.SUB => Constant(x.doubleValue - y.doubleValue)
+ case nme.MUL => Constant(x.doubleValue * y.doubleValue)
+ case nme.DIV => Constant(x.doubleValue / y.doubleValue)
+ case nme.MOD => Constant(x.doubleValue % y.doubleValue)
+ case _ => null
+ }
+
+ private def foldBinop(op: Name, x: Constant, y: Constant): Constant = {
+ val optag =
+ if (x.tag == y.tag) x.tag
+ else if (x.isNumeric && y.isNumeric) math.max(x.tag, y.tag)
+ else NoTag
+
+ try optag match {
+ case BooleanTag => foldBooleanOp(op, x, y)
+ case ByteTag | ShortTag | CharTag | IntTag => foldSubrangeOp(op, x, y)
+ case LongTag => foldLongOp(op, x, y)
+ case FloatTag => foldFloatOp(op, x, y)
+ case DoubleTag => foldDoubleOp(op, x, y)
+ case StringTag if op == nme.ADD => Constant(x.stringValue + y.stringValue)
+ case _ => null
+ }
+ catch {
+ case ex: ArithmeticException => null
+ }
+ }
+}
diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala
index ec2f46d5d..9f7956203 100644
--- a/src/dotty/tools/dotc/typer/Implicits.scala
+++ b/src/dotty/tools/dotc/typer/Implicits.scala
@@ -8,6 +8,7 @@ import util.Positions._
import Contexts._
import Types._
import Flags._
+import Mode.ImplicitsDisabled
import Denotations._
import NameOps._
import SymDenotations._
@@ -27,7 +28,7 @@ object Implicits {
/** A common base class of contextual implicits and of-type implicits which
* represents as set of implicit references.
*/
- abstract class ImplicitRefs extends Compatibility with Normalizing {
+ abstract class ImplicitRefs extends Compatibility {
/** The implicit references */
def refs: Set[TermRef]
@@ -207,7 +208,7 @@ trait Implicits { self: Typer =>
def typedImplicit(ref: TermRef)(implicit ctx: Context): SearchResult = {
val id = Ident(ref).withPos(pos)
val tree =
- if (argument.isEmpty) adapt(id, Mode.Expr, pt)
+ if (argument.isEmpty) adapt(id, pt)
else typedApply(id, ref, argument :: Nil, pt)
if (tree.tpe.isError) NoImplicitMatches // todo: replace by checking if local errors were reported in ctx.
else SearchSuccess(ref, tree, ctx.typerState)
@@ -220,7 +221,7 @@ trait Implicits { self: Typer =>
*/
private def rankImplicits(pending: List[TermRef], acc: List[SearchSuccess]): List[SearchSuccess] = pending match {
case ref :: pending1 =>
- typedImplicit(ref)(ctx.fresh.withNewTyperState.silent) match {
+ typedImplicit(ref)(ctx.fresh.withNewTyperState.addMode(ImplicitsDisabled)) match {
case fail: SearchFailure =>
rankImplicits(pending1, acc)
case best @ SearchSuccess(bestRef, _, _) =>
diff --git a/src/dotty/tools/dotc/typer/ImportInfo.scala b/src/dotty/tools/dotc/typer/ImportInfo.scala
index 4d173e10e..1a720f9d1 100644
--- a/src/dotty/tools/dotc/typer/ImportInfo.scala
+++ b/src/dotty/tools/dotc/typer/ImportInfo.scala
@@ -9,7 +9,7 @@ import util.SimpleMap
import Symbols._, Names._, Denotations._, Types._, Contexts._, StdNames._, Flags._
/** Info relating to an import clause */
-case class ImportInfo(sym: Symbol, selectors: List[untpd.Tree], scopeNestingLevel: Int)(implicit ctx: Context) {
+case class ImportInfo(sym: Symbol, selectors: List[untpd.Tree])(implicit ctx: Context) {
/** The (TermRef) type of the qualifier of the import clause */
def site(implicit ctx: Context): Type = {
diff --git a/src/dotty/tools/dotc/typer/Mode.scala b/src/dotty/tools/dotc/typer/Mode.scala
index 11f2ac458..d71c0c020 100644
--- a/src/dotty/tools/dotc/typer/Mode.scala
+++ b/src/dotty/tools/dotc/typer/Mode.scala
@@ -1,20 +1,35 @@
package dotty.tools.dotc.typer
+import collection.mutable
+
case class Mode(val bits: Int) extends AnyVal {
+ import Mode._
def | (that: Mode) = Mode(bits | that.bits)
def & (that: Mode) = Mode(bits & that.bits)
def &~ (that: Mode) = Mode(bits & ~that.bits)
def is (that: Mode) = (bits & that.bits) == that.bits
+
+ def isExpr = (this & PatternOrType) == None
+
+ override def toString =
+ (0 until 31).filter(i => (bits & (1 << i)) != 0).map(modeName).mkString("Mode(", ",", ")")
}
object Mode {
- val None = Mode(1 << 0)
+// val None = Mode(1 << 0)
+ val None = Mode(0)
+
+ private var modeName = new Array[String](32)
- val Expr = Mode(1 << 1)
- val Pattern = Mode(1 << 2)
- val Type = Mode(1 << 3)
+ def newMode(bit: Int, name: String): Mode = {
+ modeName(bit) = name
+ Mode(1 << bit)
+ }
- val Fun = Mode(1 << 4)
+ val Pattern = newMode(0, "Pattern")
+ val Type = newMode(1, "Type")
+ val ImplicitsDisabled = newMode(2, "ImplicitsDisabled")
+ val PatternOrType = Pattern | Type
} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index 56469e604..529e48080 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -135,7 +135,7 @@ class Namer { typer: Typer =>
/** A new context that summarizes an import statement */
def importContext(sym: Symbol, selectors: List[Tree])(implicit ctx: Context) =
- ctx.fresh.withImportInfo(ImportInfo(sym, selectors, ctx.scopeNestingLevel))
+ ctx.fresh.withImportInfo(ImportInfo(sym, selectors))
/** A new context for the interior of a class */
def inClassContext(cls: ClassSymbol, selfName: TermName)(implicit ctx: Context): Context = {
@@ -210,7 +210,7 @@ class Namer { typer: Typer =>
if (tree.isClassDef) classDefSig(tree, sym.asClass)(localContext)
else typeDefSig(tree, sym)(localContext.withNewScope)
case imp: Import =>
- val expr1 = typedAhead(imp.expr)
+ val expr1 = typedAheadExpr(imp.expr)
ImportType(SharedTree(expr1))
}
@@ -219,13 +219,19 @@ class Namer { typer: Typer =>
}
/** Typecheck tree during completion, and remember result in typedtree map */
- def typedAhead(tree: Tree, mode: Mode = Mode.Expr, pt: Type = WildcardType)(implicit ctx: Context): tpd.Tree =
- typedTree.getOrElseUpdate(tree, typer.typedExpanded(tree, mode, pt))
+ private def typedAheadImpl(tree: Tree, pt: Type)(implicit ctx: Context): tpd.Tree =
+ typedTree.getOrElseUpdate(tree, typer.typedExpanded(tree, pt))
+
+ def typedAheadType(tree: Tree, pt: Type = WildcardType)(implicit ctx: Context): tpd.Tree =
+ typedAheadImpl(tree, WildcardType)(ctx retractMode Mode.PatternOrType addMode Mode.Type)
+
+ def typedAheadExpr(tree: Tree, pt: Type = WildcardType)(implicit ctx: Context): tpd.Tree =
+ typedAheadImpl(tree, pt)(ctx retractMode Mode.PatternOrType)
/** Enter and typecheck parameter list */
def completeParams(params: List[MemberDef])(implicit ctx: Context) = {
enterSyms(params)
- for (param <- params) typedAhead(param)
+ for (param <- params) typedAheadExpr(param)
}
/** The type signature of a ValDef or DefDef
@@ -251,9 +257,9 @@ class Namer { typer: Typer =>
tp & itpe
}
}
- inherited orElse typedAhead(mdef.rhs).tpe
+ inherited orElse typedAheadExpr(mdef.rhs).tpe
}
- paramFn(typedAhead(mdef.tpt, Mode.Type, pt).tpe)
+ paramFn(typedAheadType(mdef.tpt, pt).tpe)
}
/** The type signature of a DefDef with given symbol */
@@ -280,7 +286,7 @@ class Namer { typer: Typer =>
}
if (isConstructor) {
// set result type tree to unit, but set the current class as result type of the symbol
- typedAhead(ddef.tpt, Mode.Type, defn.UnitType)
+ typedAheadType(ddef.tpt, defn.UnitType)
wrapMethType(sym.owner.typeConstructor.appliedTo(typeParams map (_.symRef)))
}
else valOrDefDefSig(ddef, sym, wrapMethType)
@@ -289,7 +295,7 @@ class Namer { typer: Typer =>
def typeDefSig(tdef: TypeDef, sym: Symbol)(implicit ctx: Context): Type = {
completeParams(tdef.tparams)
val tparamSyms = tdef.tparams map symbolOfTree
- val rhsType = typedAhead(tdef.rhs, Mode.Type).tpe
+ val rhsType = typedAheadType(tdef.rhs).tpe
rhsType match {
case bounds: TypeBounds =>
@@ -306,9 +312,9 @@ class Namer { typer: Typer =>
def parentType(constr: untpd.Tree): Type = {
val Trees.Select(Trees.New(tpt), _) = TreeInfo.methPart(constr)
- val ptype = typedAhead(tpt, Mode.Type).tpe
+ val ptype = typedAheadType(tpt).tpe
if (ptype.uninstantiatedTypeParams.isEmpty) ptype
- else typedAhead(constr, Mode.Expr).tpe
+ else typedAheadExpr(constr).tpe
}
val TypeDef(_, _, impl @ Template(_, parents, self, body)) = cdef
@@ -322,7 +328,7 @@ class Namer { typer: Typer =>
enterSyms(params)
val parentTypes = parents map parentType
val parentRefs = ctx.normalizeToRefs(parentTypes, cls, decls)
- val optSelfType = if (self.tpt.isEmpty) NoType else typedAhead(self.tpt, Mode.Type).tpe
+ val optSelfType = if (self.tpt.isEmpty) NoType else typedAheadType(self.tpt).tpe
enterSyms(rest)(inClassContext(cls, self.name))
ClassInfo(cls.owner.thisType, cls, parentRefs, decls, optSelfType)
}
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 1c4611792..2734807a6 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -93,9 +93,18 @@ class Typer extends Namer with Applications with Implicits {
* (2) Change imported symbols to selections
*
*/
- def typedIdent(tree: untpd.Ident, mode: Mode)(implicit ctx: Context): Tree = {
+ def typedIdent(tree: untpd.Ident)(implicit ctx: Context): Tree = {
val name = tree.name
+ /** Does this identifier appear as a constructor of a pattern? */
+ def isPatternConstr =
+ if (ctx.mode.isExpr && (ctx.outer.mode is Mode.Pattern))
+ ctx.outer.tree match {
+ case Apply(`tree`, _) => true
+ case _ => false
+ }
+ else false
+
/** A symbol qualifies if it exists and is not stale. Stale symbols
* are made to disappear here. In addition,
* if we are in a constructor of a pattern, we ignore all definitions
@@ -105,7 +114,7 @@ class Typer extends Namer with Applications with Implicits {
*/
def qualifies(sym: Symbol): Boolean = !(
sym.isAbsent
- || (mode is Mode.Pattern | Mode.Fun) && (sym is (Method, butNot = Accessor))
+ || isPatternConstr && (sym is (Method, butNot = Accessor))
)
/** Find the denotation of enclosing `name` in given context `ctx`.
@@ -219,7 +228,7 @@ class Typer extends Namer with Applications with Implicits {
// begin typedIdent
val startingContext = // ignore current variable scope in patterns to enforce linearity
- if (mode is Mode.Pattern) ctx.outer else ctx
+ if (ctx.mode is Mode.Pattern) ctx.outer else ctx
val rawType = findRef(NoType, BindingPrec.nothingBound, NoContext)
val ownType =
@@ -231,8 +240,8 @@ class Typer extends Namer with Applications with Implicits {
tree.withType(ownType)
}
- def typedSelect(tree: untpd.Select, mode: Mode, pt: Type)(implicit ctx: Context): Tree = {
- val qual1 = typed(tree.qualifier, Mode.Expr, RefinedType(WildcardType, tree.name, pt))
+ def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = {
+ val qual1 = typedExpr(tree.qualifier, RefinedType(WildcardType, tree.name, pt))
val ownType = typedSelection(qual1.exprType, tree.name, tree.pos)
if (!ownType.isError) checkAccessible(ownType, qual1.isInstanceOf[Super], tree.pos)
tree.withType(ownType).derivedSelect(qual1, tree.name)
@@ -245,14 +254,22 @@ class Typer extends Namer with Applications with Implicits {
def typedArgs: List[tpd.Tree] = {
if (myTypedArgs == null)
- myTypedArgs = args mapconserve (typed(_, pt = WildcardType))
+ myTypedArgs = args mapconserve (typed(_))
myTypedArgs
}
+
+ def expected: String = {
+ val result = resultType match {
+ case tp: WildcardType => ""
+ case tp => s"and expected result type $tp"
+ }
+ s"arguments (${typedArgs map (_.tpe.show) mkString ", "})$result"
+ }
}
- def typedApply(tree: untpd.Apply, mode: Mode, pt: Type)(implicit ctx: Context): Tree = {
+ def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = {
val proto = new FunProtoType(tree.args, pt)
- val fun1 = typed(tree.fun, Mode.Expr, proto)
+ val fun1 = typedExpr(tree.fun, proto)
TreeInfo.methPart(fun1).tpe match {
case funRef: TermRef =>
val app =
@@ -274,7 +291,7 @@ class Typer extends Namer with Applications with Implicits {
}
def typedAnnotation(annot: untpd.Tree)(implicit ctx: Context): Tree =
- typed(annot, Mode.Expr, defn.AnnotationClass.typeConstructor)
+ typed(annot, defn.AnnotationClass.typeConstructor)
def typedValDef(vdef: untpd.ValDef, sym: Symbol)(implicit ctx: Context) = {
val Trees.ValDef(mods, name, tpt, rhs) = vdef
@@ -308,7 +325,7 @@ class Typer extends Namer with Applications with Implicits {
val constr1 = typed(constr).asInstanceOf[DefDef]
val parents1 = parents mapconserve (typed(_))
val self1 = self.withType(NoType).derivedValDef(
- typedModifiers(self.mods), self.name, typed(self.tpt), EmptyTree)
+ typedModifiers(self.mods), self.name, typedType(self.tpt), EmptyTree)
val localDummy = ctx.newLocalDummy(cls, impl.pos)
val body1 = typedStats(body, localDummy)(inClassContext(cls, self.name))
@@ -327,11 +344,11 @@ class Typer extends Namer with Applications with Implicits {
}
def typedImport(imp: untpd.Import, sym: Symbol)(implicit ctx: Context): Import = {
- val expr1 = typed(imp.expr)
+ val expr1 = typedExpr(imp.expr)
imp.withType(sym.symRef).derivedImport(expr1, imp.selectors)
}
- def typedExpanded(tree: untpd.Tree, mode: Mode = Mode.Expr, pt: Type = WildcardType)(implicit ctx: Context): Tree = {
+ def typedExpanded(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = {
val sym = symOfTree.remove(tree).getOrElse(NoSymbol)
sym.ensureCompleted()
def localContext = ctx.fresh.withOwner(sym)
@@ -349,7 +366,7 @@ class Typer extends Namer with Applications with Implicits {
case tree: untpd.Import =>
typedImport(tree, sym)
case tree: untpd.TypeTree =>
- if (!tree.isEmpty) typed(tree.original, Mode.Type, pt)
+ if (!tree.isEmpty) typedType(tree.original, pt)
else {
assert(!pt.isInstanceOf[WildcardType])
tree.withType(pt)
@@ -360,7 +377,7 @@ class Typer extends Namer with Applications with Implicits {
}
}
- def typed(tree: untpd.Tree, mode: Mode = Mode.Expr, pt: Type = WildcardType)(implicit ctx: Context): Tree = {
+ def typed(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = {
val xtree =
tree match {
case tree: untpd.MemberDef =>
@@ -370,11 +387,11 @@ class Typer extends Namer with Applications with Implicits {
}
case _ => tree
}
- typedExpanded(xtree, mode, pt)
+ typedExpanded(xtree, pt)
}
- def typedTrees(trees: List[untpd.Tree], mode: Mode = Mode.Expr)(implicit ctx: Context): List[Tree] =
- trees mapconserve (typed(_, mode))
+ def typedTrees(trees: List[untpd.Tree])(implicit ctx: Context): List[Tree] =
+ trees mapconserve (typed(_))
def typedStats(stats: List[untpd.Tree], exprOwner: Symbol)(implicit ctx: Context): List[tpd.Tree] = {
val buf = new mutable.ListBuffer[Tree]
@@ -396,10 +413,170 @@ class Typer extends Namer with Applications with Implicits {
}
def typedExpr(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree =
- typed(tree, Mode.Expr, pt)
+ typed(tree, pt)(ctx retractMode Mode.PatternOrType)
def typedType(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree =
- typed(tree, Mode.Type, pt)
+ typed(tree, pt)(ctx addMode Mode.Type)
+ def typedPattern(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree =
+ typed(tree, pt)(ctx addMode Mode.Pattern)
+
+ def tryEither[T](op: Context => T)(fallBack: => T)(implicit ctx: Context) = {
+ val nestedCtx = ctx.fresh.withNewTyperState
+ val result = op(nestedCtx)
+ if (nestedCtx.reporter.hasErrors)
+ fallBack
+ else {
+ nestedCtx.typerState.commit()
+ result
+ }
+ }
+
+ def tryInsertApply(tree: Tree, pt: Type)(fallBack: => Tree)(implicit ctx: Context): Tree =
+ tryEither {
+ implicit ctx => typedSelect(Trees.Select(untpd.TypedSplice(tree), nme.apply), pt)
+ } {
+ fallBack
+ }
- def adapt(tree: Tree, mode: Mode, pt: Type): Tree = ???
+ def tryInsertApplyIfFunProto(tree: Tree, pt: Type)(fallBack: => Tree)(implicit ctx: Context): Tree = pt match {
+ case pt: FunProtoType => tryInsertApply(tree, pt)(fallBack)
+ case _ => fallBack
+ }
+
+ def errorTree(tree: Trees.Tree[_], msg: => String)(implicit ctx: Context): tpd.Tree = {
+ ctx.error(msg, tree.pos)
+ tree withType ErrorType
+ }
+
+ def expected(tp: Type)(implicit ctx: Context): String = tp match {
+ case tp: FunProtoType => tp.expected
+ case _ => s"expected type ${tp.show}"
+ }
+
+ def summarize(tpe: Type): String = ???
+
+
+
+ /**
+ * (-1) For expressions with annotated types, let AnnotationCheckers decide what to do
+ * (0) Convert expressions with constant types to literals (unless in interactive/scaladoc mode)
+ */
+ /** Perform the following adaptations of expression, pattern or type `tree` wrt to
+ * given prototype `pt`:
+ * (1) Resolve overloading
+ * (2) Apply parameterless functions
+ * (3) Apply polymorphic types to fresh instances of their type parameters and
+ * store these instances in context.undetparams,
+ * unless followed by explicit type application.
+ * (4) Do the following to unapplied methods used as values:
+ * (4.1) If the method has only implicit parameters pass implicit arguments
+ * (4.2) otherwise, if `pt` is a function type and method is not a constructor,
+ * convert to function by eta-expansion,
+ * (4.3) otherwise, if the method is nullary with a result type compatible to `pt`
+ * and it is not a constructor, apply it to ()
+ * otherwise issue an error
+ * (5) Convert constructors in a pattern as follows:
+ * (5.1) If constructor refers to a case class factory, set tree's type to the unique
+ * instance of its primary constructor that is a subtype of the expected type.
+ * (5.2) If constructor refers to an extractor, convert to application of
+ * unapply or unapplySeq method.
+ *
+ * (6) Convert all other types to TypeTree nodes.
+ * (7) When in TYPEmode but not FUNmode or HKmode, check that types are fully parameterized
+ * (7.1) In HKmode, higher-kinded types are allowed, but they must have the expected kind-arity
+ * (8) When in both EXPRmode and FUNmode, add apply method calls to values of object type.
+ * (9) If there are undetermined type variables and not POLYmode, infer expression instance
+ * Then, if tree's type is not a subtype of expected type, try the following adaptations:
+ * (10) If the expected type is Byte, Short or Char, and the expression
+ * is an integer fitting in the range of that type, convert it to that type.
+ * (11) Widen numeric literals to their expected type, if necessary
+ * (12) When in mode EXPRmode, convert E to { E; () } if expected type is scala.Unit.
+ * (13) When in mode EXPRmode, apply AnnotationChecker conversion if expected type is annotated.
+ * (14) When in mode EXPRmode, apply a view
+ * If all this fails, error
+ */
+ def adapt(tree: Tree, pt: Type)(implicit ctx: Context): Tree = {
+
+ def overloadError(prefix: String, suffix: String, alts: List[TermRef]) =
+ errorTree(tree,
+ s"""$prefix alternatives of ${alts.head.show} with types
+ | ${alts map (_.info) mkString "\n "}
+ |$suffix ${expected(pt)}""".stripMargin)
+
+ def notAFunctionError() = {
+ val fn = summarize(TreeInfo.methPart(tree).tpe)
+ val more = tree match {
+ case Apply(_, _) => " more"
+ case _ => ""
+ }
+ errorTree(tree, s"$fn does not take$more parameters")
+ }
+
+ def typeMismatch(tree: Tree, pt: Type)(implicit ctx: Context): Tree = ???
+
+ def adaptOverloaded(ref: TermRef) = {
+ val alts = ref.denot.alternatives map (alt =>
+ TermRef.withSym(ref.prefix, alt.symbol.asTerm))
+ resolveOverloaded(alts, pt) match {
+ case alt :: Nil =>
+ adapt(tree.withType(alt), pt)
+ case Nil =>
+ tryInsertApplyIfFunProto(tree, pt) {
+ overloadError("none of the overloaded", "match", alts)
+ }
+ case alts =>
+ overloadError("Ambiguous overload. The ", "both match", alts take 2)
+ }
+ }
+
+ def adaptToArgs(tp: Type, pt: FunProtoType) = tp match {
+ case _: MethodType => tree
+ case _ => tryInsertApply(tree, pt) { notAFunctionError() }
+ }
+
+ def adaptNoArgs(tp: Type) = tp match {
+ case tp: ExprType =>
+ adapt(tree.withType(tp.resultType), pt)
+ case tp: ImplicitMethodType =>
+ val args = tp.paramTypes map (inferImplicit(_, EmptyTree, tree.pos))
+ adapt(tpd.Apply(tree, args), pt)
+ case tp: MethodType =>
+ if (defn.isFunctionType(pt) && !tree.symbol.isConstructor)
+ ??? // etaExpand()
+ else if (tp.paramTypes.isEmpty)
+ adapt(tpd.Apply(tree, Nil), pt)
+ else
+ errorTree(tree,
+ s"""missing arguments for ${tree.symbol.show}
+ |follow this method with `_' if you want to treat it as a partially applied function""".stripMargin)
+ case _ =>
+ if (tp <:< pt) tree else adaptToSubType(tp)
+ }
+
+ def adaptToSubType(tp: Type): Tree = {
+ val adapted = ConstFold(tree, pt)
+ if (adapted ne EmptyTree) return adapted
+ if (ctx.mode.isExpr) {
+ if (pt.typeSymbol == defn.UnitClass)
+ return tpd.Block(tree :: Nil, Literal(Constant()))
+ val adapted = inferView(tree, pt)
+ if (adapted ne EmptyTree) return adapted
+ }
+ typeMismatch(tree, pt)
+ }
+
+ tree.tpe.widen match {
+ case ref: TermRef =>
+ adaptOverloaded(ref)
+ case pt: PolyType =>
+ val tracked = ctx.track(pt)
+ val tvars = ctx.newTypeVars(tracked)
+ adapt(tpd.TypeApply(tree, tvars map (tpd.TypeTree(_))), pt)
+ case tp =>
+ pt match {
+ case pt: FunProtoType => adaptToArgs(tp, pt)
+ case _ => adaptNoArgs(tp)
+ }
+ }
+ }
} \ No newline at end of file