diff options
author | Martin Odersky <odersky@gmail.com> | 2013-07-21 14:42:02 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2013-07-21 14:42:02 +0200 |
commit | 1ed37543f0dc893ba697c212c310063541018f5c (patch) | |
tree | c0e76ae1e556ad40bb3e6c3ff6aef90b2ce342ef /src/dotty/tools/dotc | |
parent | 7e1bd23bf01c6949e08785eb5afc0fcf46b72afb (diff) | |
download | dotty-1ed37543f0dc893ba697c212c310063541018f5c.tar.gz dotty-1ed37543f0dc893ba697c212c310063541018f5c.tar.bz2 dotty-1ed37543f0dc893ba697c212c310063541018f5c.zip |
Added code for adapt and more.
- Pushed mode into context
- Elimintaed scope nesting level
- Fixed a desugar bug
- Added constant folding
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r-- | src/dotty/tools/dotc/ast/Desugar.scala | 36 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Contexts.scala | 21 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Definitions.scala | 38 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/TyperState.scala | 11 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Applications.scala | 55 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/ConstFold.scala | 183 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Implicits.scala | 7 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/ImportInfo.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Mode.scala | 25 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Namer.scala | 30 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 217 |
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 |