aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/dotc/ast/CheckTrees.scala4
-rw-r--r--src/dotty/tools/dotc/ast/Desugar.scala68
-rw-r--r--src/dotty/tools/dotc/ast/TreeInfo.scala15
-rw-r--r--src/dotty/tools/dotc/ast/TypedTrees.scala3
-rw-r--r--src/dotty/tools/dotc/core/Constraints.scala89
-rw-r--r--src/dotty/tools/dotc/core/Contexts.scala26
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala14
-rw-r--r--src/dotty/tools/dotc/core/Denotations.scala7
-rw-r--r--src/dotty/tools/dotc/core/Diagnostic.scala10
-rw-r--r--src/dotty/tools/dotc/core/Flags.scala16
-rw-r--r--src/dotty/tools/dotc/core/Substituters.scala60
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala85
-rw-r--r--src/dotty/tools/dotc/core/Symbols.scala2
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala336
-rw-r--r--src/dotty/tools/dotc/core/TypeComparers.scala439
-rw-r--r--src/dotty/tools/dotc/core/TyperState.scala43
-rw-r--r--src/dotty/tools/dotc/core/Types.scala46
-rw-r--r--src/dotty/tools/dotc/core/pickling/PickleBuffer.scala2
-rw-r--r--src/dotty/tools/dotc/core/pickling/UnPickler.scala12
-rw-r--r--src/dotty/tools/dotc/printing/RefinedPrinter.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala645
-rw-r--r--src/dotty/tools/dotc/typer/Inferencing.scala82
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala1
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala88
-rw-r--r--src/dotty/tools/io/package.scala2
25 files changed, 1509 insertions, 588 deletions
diff --git a/src/dotty/tools/dotc/ast/CheckTrees.scala b/src/dotty/tools/dotc/ast/CheckTrees.scala
index 4c3413ada..4790f231b 100644
--- a/src/dotty/tools/dotc/ast/CheckTrees.scala
+++ b/src/dotty/tools/dotc/ast/CheckTrees.scala
@@ -36,7 +36,7 @@ object CheckTrees {
case NamedArg(argName, _) =>
check(argName == name)
case SeqLiteral(_, _) =>
- check(defn.RepeatedParamClasses contains formal.typeSymbol)
+ check(formal.isRepeatedParam)
case _ =>
check(arg.isValue)
}
@@ -187,7 +187,7 @@ object CheckTrees {
case nme.unapplySeq =>
// args need to be wrapped in (...: _*)
check(args.length == 1)
- check(args.head.tpe.typeSymbol == defn.RepeatedParamClass)
+ check(args.head.tpe.isRepeatedParam)
case nme.unapply =>
val rtp = funtpe.resultType
val rsym = rtp.dealias.typeSymbol
diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala
index faa015793..ae1a06a74 100644
--- a/src/dotty/tools/dotc/ast/Desugar.scala
+++ b/src/dotty/tools/dotc/ast/Desugar.scala
@@ -34,7 +34,7 @@ object desugar {
}
}
- def defDef(meth: DefDef, isPrimaryConstructor: Boolean = false): DefDef = {
+ def defDef(meth: DefDef, isPrimaryConstructor: Boolean = false): Tree = {
val DefDef(mods, name, tparams, vparamss, tpt, rhs) = meth
val epbuf = new ListBuffer[ValDef]
val tparams1 = tparams mapConserve {
@@ -49,7 +49,8 @@ object desugar {
case tparam =>
tparam
}
- epbuf.toList match {
+
+ val meth1 = epbuf.toList match {
case Nil =>
meth
case evidenceParams =>
@@ -61,6 +62,42 @@ object desugar {
}
meth.derivedDefDef(mods, name, tparams1, vparamss1, tpt, rhs)
}
+
+ def take(vparamss: List[List[ValDef]], n: Int): List[List[ValDef]] = vparamss match {
+ case vparams :: vparamss1 =>
+ val len = vparams.length
+ if (len <= n) vparams :: take(vparamss1, n - len) else Nil
+ case _ =>
+ Nil
+ }
+
+ def defaultGetters(vparamss: List[List[ValDef]], n: Int = 0): List[DefDef] = vparamss match {
+ case (vparam :: vparams) :: vparamss1 =>
+ def defaultGetter: DefDef =
+ DefDef(
+ mods = vparam.mods & AccessFlags,
+ name = meth.name.defaultGetterName(n + 1),
+ tparams = meth.tparams,
+ vparamss = take(meth.vparamss, n),
+ tpt = TypeTree(),
+ rhs = vparam.rhs)
+ val rest = defaultGetters(vparams :: vparamss1, n + 1)
+ if (vparam.rhs.isEmpty) rest else defaultGetter :: rest
+ case Nil :: vparamss1 =>
+ defaultGetters(vparamss1)
+ case nil =>
+ Nil
+ }
+
+ val defGetters = defaultGetters(vparamss)
+ if (defGetters.isEmpty) meth1
+ else {
+ val mods1 = meth1.mods | DefaultParameterized
+ val vparamss1 = vparamss map (_ map (vparam =>
+ vparam.derivedValDef(vparam.mods, vparam.name, vparam.tpt, EmptyTree)))
+ val meth2 = meth1.derivedDefDef(mods1, meth1.name, meth1.tparams, vparamss1, meth1.tpt, meth1.rhs)
+ Thicket(meth2 :: defGetters)
+ }
}
def typeDef(tdef: TypeDef)(implicit ctx: Context): Tree = {
@@ -81,7 +118,10 @@ object desugar {
val TypeDef(
mods, name, impl @ Template(constr0, parents, self, body)) = cdef
- val constr1 = defDef(constr0, isPrimaryConstructor = true)
+ val (constr1, defaultGetters) = defDef(constr0, isPrimaryConstructor = true) match {
+ case meth: DefDef => (meth, Nil)
+ case Thicket((meth: DefDef) :: defaults) => (meth, defaults)
+ }
val tparams = constr1.tparams.map(tparam => tparam.derivedTypeDef(
Modifiers(Param), tparam.name, tparam.rhs, tparam.tparams))
@@ -129,10 +169,18 @@ object desugar {
}
else Nil
- val caseCompanions =
+ def anyRef = ref(defn.AnyRefAlias.typeConstructor)
+
+ def companionDefs(parent: Tree, defs: List[Tree]) =
+ moduleDef(
+ ModuleDef(
+ Modifiers(Synthetic), name.toTermName,
+ Template(emptyConstructor, parent :: Nil, EmptyValDef(), defs))).toList
+
+ val companions =
if (mods is Case) {
val parent =
- if (tparams.nonEmpty) ref(defn.AnyRefAlias.typeConstructor)
+ if (tparams.nonEmpty) anyRef
else (vparamss :\ classTypeRef) ((vparams, restpe) => Function(vparams map (_.tpt), restpe))
val applyMeths =
if (mods is Abstract) Nil
@@ -141,12 +189,10 @@ object desugar {
val unapplyParam = makeSyntheticParameter(tpt = classTypeRef)
DefDef(synthetic, nme.unapply, tparams, (unapplyParam :: Nil) :: Nil, EmptyTree, This(EmptyTypeName))
}
- moduleDef(
- ModuleDef(
- Modifiers(Synthetic), name.toTermName,
- Template(emptyConstructor, parent :: Nil, EmptyValDef(), applyMeths ::: unapplyMeth :: Nil))
- ).toList
+ companionDefs(parent, applyMeths ::: unapplyMeth :: defaultGetters)
}
+ else if (defaultGetters.nonEmpty)
+ companionDefs(anyRef, defaultGetters)
else Nil
val implicitWrappers =
@@ -163,7 +209,7 @@ object desugar {
val cdef1 = cdef.derivedTypeDef(mods, name,
impl.derivedTemplate(constr, parents, self,
constr1.tparams ::: constr1.vparamss.flatten ::: body ::: caseClassMeths))
- Thicket.make(cdef1 :: caseCompanions ::: implicitWrappers)
+ Thicket.make(cdef1 :: companions ::: implicitWrappers)
}
/** Expand to:
diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala
index 7e9c404eb..a3af19263 100644
--- a/src/dotty/tools/dotc/ast/TreeInfo.scala
+++ b/src/dotty/tools/dotc/ast/TreeInfo.scala
@@ -94,7 +94,7 @@ abstract class TreeInfo {
def recur(params: List[Symbol], args: List[Tree[T]]): Boolean = params match {
case Nil => args.isEmpty
case param :: params1 =>
- if (defn.RepeatedParamClasses contains param.info.typeSymbol) {
+ if (param.info.isRepeatedParam) {
for (arg <- args) f(param, arg)
true
} else args match {
@@ -128,10 +128,19 @@ abstract class TreeInfo {
case Apply(fn, _) => methPart(fn)
case TypeApply(fn, _) => methPart(fn)
case AppliedTypeTree(fn, _) => methPart(fn)
- case Block(stats, expr) if stats forall (_.isInstanceOf[ValDef[_]]) => methPart(expr)
+ case Block(stats, expr) => methPart(expr)
case _ => tree
}
+ /** The number of arguments in an application */
+ def numArgs[T >: Untyped](tree: Tree[T]): Int = tree match {
+ case Apply(fn, args) => numArgs(fn) + args.length
+ case TypeApply(fn, args) => numArgs(fn) + args.length
+ case AppliedTypeTree(fn, args) => numArgs(fn) + args.length
+ case Block(stats, expr) => numArgs(expr)
+ case _ => 0
+ }
+
/** Is symbol potentially a getter of a mutable variable?
*/
def mayBeVarGetter(sym: Symbol)(implicit ctx: Context): Boolean = {
@@ -237,7 +246,7 @@ abstract class TreeInfo {
/** Is tpt a vararg type of the form T* ? */
def isRepeatedParamType(tpt: Tree[_ >: Untyped])(implicit ctx: Context) = tpt match {
- case tpt: TypeTree[_] => defn.RepeatedParamClasses contains tpt.typeOpt.typeSymbol
+ case tpt: TypeTree[_] => tpt.typeOpt.isRepeatedParam
case AppliedTypeTree(Select(_, tpnme.REPEATED_PARAM_CLASS), _) => true
case AppliedTypeTree(Select(_, tpnme.JAVA_REPEATED_PARAM_CLASS), _) => true
case _ => false
diff --git a/src/dotty/tools/dotc/ast/TypedTrees.scala b/src/dotty/tools/dotc/ast/TypedTrees.scala
index 5e4f7342d..cce905d92 100644
--- a/src/dotty/tools/dotc/ast/TypedTrees.scala
+++ b/src/dotty/tools/dotc/ast/TypedTrees.scala
@@ -87,6 +87,9 @@ object tpd extends Trees.Instance[Type] {
blk.withType(widen(expr.tpe))
}
+ def maybeBlock(stats: List[Tree], expr: Tree)(implicit ctx: Context): Tree =
+ if (stats.isEmpty) expr else Block(stats, expr)
+
def If(cond: Tree, thenp: Tree, elsep: Tree)(implicit ctx: Context): If =
Trees.If(cond, thenp, elsep).withType(thenp.tpe | elsep.tpe).checked
diff --git a/src/dotty/tools/dotc/core/Constraints.scala b/src/dotty/tools/dotc/core/Constraints.scala
new file mode 100644
index 000000000..b997ca42a
--- /dev/null
+++ b/src/dotty/tools/dotc/core/Constraints.scala
@@ -0,0 +1,89 @@
+package dotty.tools
+package dotc
+package core
+
+import Types._, Contexts._
+import util.SimpleMap
+
+/** Constraint over undetermined type parameters
+ * @param map a map from PolyType to the type bounds that constrain the
+ * polytype's type parameters. A type parameter that does not
+ * have a constraint is represented by a `NoType` in the corresponding
+ * array entry.
+ */
+class Constraint(val map: SimpleMap[PolyType, Array[Type]]) extends AnyVal {
+
+ /** Does the constraint's domain contain the type parameters of `pt`? */
+ def contains(pt: PolyType): Boolean = map(pt) != null
+
+ /** The constraint for given type parameter `param`, or NoType if `param` is not part of
+ * the constraint domain.
+ */
+ def apply(param: PolyParam): Type = {
+ val entries = map(param.binder)
+ if (entries == null) NoType else entries(param.paramNum)
+ }
+
+ /** The constraint for the type parameters of `pt`.
+ * @pre The polytype's type parameters are contained in the constraint's domain.
+ */
+ def apply(pt: PolyType): Array[Type] = map(pt)
+
+ /** A new constraint which is derived from this constraint by adding or replacing
+ * the entries corresponding to `pt` with `entries`.
+ */
+ def updated(pt: PolyType, entries: Array[Type]) =
+ new Constraint(map.updated(pt, entries))
+
+ /** A new constraint which is derived from this constraint by removing
+ * the type parameter `param` from the domain.
+ */
+ def - (param: PolyParam) = {
+ val pt = param.binder
+ val pnum = param.paramNum
+ val entries = map(pt)
+ var noneLeft = true
+ var i = 0
+ while (noneLeft && (i < entries.length)) {
+ noneLeft = (entries(i) eq NoType) || i == pnum
+ i += 1
+ }
+ new Constraint(
+ if (noneLeft) map remove pt
+ else {
+ val newEntries = entries.clone
+ newEntries(pnum) = NoType
+ map.updated(pt, newEntries)
+ })
+ }
+
+ def +(pt: PolyType) =
+ new Constraint(map.updated(pt, pt.paramBounds.toArray))
+
+ /** A new constraint which is derived from this constraint by removing
+ * the type parameter `param` from the domain and replacing all occurrences
+ * of the parameter elsewhere in the constraint by type `tp`.
+ */
+ def replace(param: PolyParam, tp: Type)(implicit ctx: Context) = {
+ def subst(entries: Array[Type]) = {
+ var result = entries
+ var i = 0
+ while (i < entries.length) {
+ entries(i) match {
+ case oldBounds: TypeBounds =>
+ val newBounds = oldBounds.substParam(param, tp)
+ if (oldBounds ne newBounds) {
+
+ if (result eq entries) result = entries.clone
+ result(i) = newBounds
+ }
+ case _ =>
+ }
+ i += 1
+ }
+ result
+ }
+
+ new Constraint((this - param).map mapValues subst)
+ }
+}
diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala
index e2273738f..b1523144d 100644
--- a/src/dotty/tools/dotc/core/Contexts.scala
+++ b/src/dotty/tools/dotc/core/Contexts.scala
@@ -9,8 +9,11 @@ import Phases._
import Types._
import Symbols._
import Scopes._
-import TypeComparers._, NameOps._, SymDenotations._, util.Positions._
-import ast.Trees._, ast.untpd
+import NameOps._
+import SymDenotations._
+import util.Positions._
+import ast.Trees._
+import ast.untpd
import util.{FreshNameCreator, SimpleMap}
import typer._
import config.Settings._
@@ -83,9 +86,9 @@ object Contexts {
}
/** The current type comparer */
- private[this] var _typeComparer: TypeComparer = _
- protected def typeComparer_=(typeComparer: TypeComparer) = _typeComparer = typeComparer
- def typeComparer: TypeComparer = _typeComparer
+ private[this] var _typerState: TyperState = _
+ protected def typerState_=(typerState: TyperState) = _typerState = typerState
+ def typerState: TyperState = _typerState
/** The current position */
private[this] var _position: Position = _
@@ -149,6 +152,12 @@ object Contexts {
protected def moreProperties_=(moreProperties: Map[String, Any]) = _moreProperties = moreProperties
def moreProperties: Map[String, Any] = _moreProperties
+ private var _typeComparer: TypeComparer = _
+ def typeComparer: TypeComparer = {
+ if (_typeComparer == null || (_typeComparer.ctx ne this))
+ _typeComparer = new TypeComparer()(this)
+ _typeComparer
+ }
/** If -Ydebug is on, the top of the stack trace where this context
* was created, otherwise `null`.
@@ -208,7 +217,7 @@ object Contexts {
if (_condensed eq outer.condensed)
_condensed = base.initialCtx.fresh
.withPeriod(period)
- // typeComparer and its constraints is not preserved in condensed
+ // typerState and its constraint is not preserved in condensed
.withPlainPrinter(plainPrinter)
.withRefinedPrinter(refinedPrinter)
.withOwner(owner)
@@ -242,7 +251,8 @@ object Contexts {
*/
abstract class FreshContext extends CondensedContext {
def withPeriod(period: Period): this.type = { this.period = period; this }
- def withTypeComparer(typeComparer: TypeComparer): this.type = { this.typeComparer = typeComparer; 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 }
def withPlainPrinter(printer: Context => Printer): this.type = { this.plainPrinter = printer; this }
def withRefinedPrinter(printer: Context => Printer): this.type = { this.refinedPrinter = printer; this }
@@ -273,7 +283,7 @@ object Contexts {
private class InitialContext(val base: ContextBase, settings: SettingGroup) extends FreshContext {
outer = NoContext
period = InitialPeriod
- typeComparer = new TypeComparer
+ typerState = new TyperState
position = NoPosition
plainPrinter = new PlainPrinter(_)
refinedPrinter = new RefinedPrinter(_)
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index 9d7f84449..66ed61a7f 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -263,8 +263,18 @@ class Definitions(implicit ctx: Context) {
// - .linkedClass: the ClassSymbol of the enumeration (class E)
sym.owner.linkedClass.typeConstructor
- def FunctionType(args: List[Type], resultType: Type) =
- FunctionClass(args.length).typeConstructor.appliedTo(args :+ resultType)
+ object FunctionType {
+ def apply(args: List[Type], resultType: Type) =
+ FunctionClass(args.length).typeConstructor.appliedTo(args :+ resultType)
+ def unapply(ft: Type) = {
+ val tsym = ft.typeSymbol
+ lazy val targs = ft.typeArgs
+ if ((FunctionClasses contains tsym) &&
+ (targs.length - 1 <= MaxFunctionArity) &&
+ (FunctionClass(targs.length - 1) == tsym)) Some(targs.init, targs.last)
+ else None
+ }
+ }
// ----- Symbol sets ---------------------------------------------------
diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala
index 87fc33a6c..cb010ed8e 100644
--- a/src/dotty/tools/dotc/core/Denotations.scala
+++ b/src/dotty/tools/dotc/core/Denotations.scala
@@ -449,6 +449,7 @@ object Denotations {
* is still a member of its enclosing package, then the whole flock
* is brought forward to be valid in the new runId. Otherwise
* the symbol is stale, which constitutes an internal error.
+ * TODO: Ensure that a subclass is renewed whenever one of its parents is.
*/
def current(implicit ctx: Context): SingleDenotation = {
val currentPeriod = ctx.period
@@ -529,6 +530,8 @@ object Denotations {
final def toDenot(pre: Type)(implicit ctx: Context) = this
final def containsSig(sig: Signature)(implicit ctx: Context) =
exists && signature == sig
+ final def filterWithPredicate(p: SingleDenotation => Boolean): PreDenotation =
+ if (p(this)) this else NoDenotation
final def filterDisjoint(denots: PreDenotation)(implicit ctx: Context): SingleDenotation =
if (denots.containsSig(signature)) NoDenotation else this
def disjointAsSeenFrom(denots: PreDenotation, pre: Type)(implicit ctx: Context): SingleDenotation =
@@ -598,6 +601,8 @@ object Denotations {
/** Group contains a denotation with given signature */
def containsSig(sig: Signature)(implicit ctx: Context): Boolean
+ def filterWithPredicate(p: SingleDenotation => Boolean): PreDenotation
+
/** Keep only those denotations in this group which have a signature
* that's not already defined by `denots`.
*/
@@ -627,6 +632,8 @@ object Denotations {
def toDenot(pre: Type)(implicit ctx: Context) = (denots1 toDenot pre) & (denots2 toDenot pre, pre)
def containsSig(sig: Signature)(implicit ctx: Context) =
(denots1 containsSig sig) || (denots2 containsSig sig)
+ def filterWithPredicate(p: SingleDenotation => Boolean): PreDenotation =
+ derivedUnion(denots1 filterWithPredicate p, denots2 filterWithPredicate p)
def filterDisjoint(denots: PreDenotation)(implicit ctx: Context): PreDenotation =
derivedUnion(denots1 filterDisjoint denots, denots2 filterDisjoint denots)
def disjointAsSeenFrom(denots: PreDenotation, pre: Type)(implicit ctx: Context): PreDenotation =
diff --git a/src/dotty/tools/dotc/core/Diagnostic.scala b/src/dotty/tools/dotc/core/Diagnostic.scala
new file mode 100644
index 000000000..e1b7ee848
--- /dev/null
+++ b/src/dotty/tools/dotc/core/Diagnostic.scala
@@ -0,0 +1,10 @@
+package dotty.tools
+package dotc
+package core
+
+import util.SourcePosition
+import reporting.Reporter
+
+class Diagnostic(msgFn: => String, val pos: SourcePosition, severity: Reporter.Severity.Value) {
+ lazy val msg: String = msgFn
+}
diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala
index 9f4cce728..82fd86c05 100644
--- a/src/dotty/tools/dotc/core/Flags.scala
+++ b/src/dotty/tools/dotc/core/Flags.scala
@@ -291,8 +291,8 @@ object Flags {
/** A super accessor */
final val SuperAccessor = termFlag(27, "<superaccessor>")
- /** A parameter with a default value */
- final val DefaultParam = termFlag(28, "<defaultparam>")
+ /** A method that has default params */ // TODO: drop
+ final val DefaultParameterized = termFlag(28, "<defaultparam>")
/** Symbol is initialized to the default value, e.g. var x: T = _ */
final val DefaultInit = termFlag(29, "<defaultinit>")
@@ -360,6 +360,12 @@ object Flags {
/** A definition that's initialized before the super call (Scala 2.x only) */
final val Scala2PreSuper = termFlag(58, "<presuper>")
+ /** A method that is known to have inherited default parameters */
+ final val InheritedDefaultParams = termFlag(59, "<inherited-default-param>")
+
+ /** A method that is known to no default parameters */
+ final val NoDefaultParams = termFlag(60, "<no-default-param>")
+
// --------- Combined Flag Sets and Conjunctions ----------------------
/** Flags representing source modifiers */
@@ -437,6 +443,12 @@ object Flags {
/** A parameter or parameter accessor */
final val ParamOrAccessor = Param | Accessor
+ /** Has defined or inherited default parameters */
+ final val HasDefaultParams = DefaultParameterized | InheritedDefaultParams
+
+ /** Is a default parameter in Scala 2*/
+ final val DefaultParameter = allOf(Param, DefaultParameterized)
+
/** A Java interface */
final val JavaInterface = allOf(JavaDefined, Trait)
diff --git a/src/dotty/tools/dotc/core/Substituters.scala b/src/dotty/tools/dotc/core/Substituters.scala
index 7a7481293..26095450e 100644
--- a/src/dotty/tools/dotc/core/Substituters.scala
+++ b/src/dotty/tools/dotc/core/Substituters.scala
@@ -7,22 +7,6 @@ import Types._, Symbols._, Contexts._
*/
trait Substituters { this: Context =>
- final def subst(tp: Type, from: BoundType, to: Type, map: SubstBoundMap): Type =
- tp match {
- case tp: BoundType =>
- if (tp == from) to else tp
- case tp: NamedType =>
- if (tp.symbol.isStatic) tp
- else tp.derivedNamedType(subst(tp.prefix, from, to, map))
- case _: ThisType | NoPrefix =>
- tp
- case tp: RefinedType =>
- tp.derivedRefinedType(subst(tp.parent, from, to, map), tp.refinedName, subst(tp.refinedInfo, from, to, map))
- case _ =>
- (if (map != null) map else new SubstBoundMap(from, to))
- .mapOver(tp)
- }
-
final def subst(tp: Type, from: BindingType, to: BindingType, map: SubstBindingMap): Type =
tp match {
case tp: BoundType =>
@@ -151,15 +135,43 @@ trait Substituters { this: Context =>
.mapOver(tp)
}
+ final def substParam(tp: Type, from: ParamType, to: Type, map: SubstParamMap): Type =
+ tp match {
+ case tp: BoundType =>
+ if (tp == from) to else tp
+ case tp: NamedType =>
+ if (tp.symbol.isStatic) tp
+ else tp.derivedNamedType(substParam(tp.prefix, from, to, map))
+ case _: ThisType | NoPrefix =>
+ tp
+ case tp: RefinedType =>
+ tp.derivedRefinedType(substParam(tp.parent, from, to, map), tp.refinedName, substParam(tp.refinedInfo, from, to, map))
+ case _ =>
+ (if (map != null) map else new SubstParamMap(from, to))
+ .mapOver(tp)
+ }
+
+ final def substParams(tp: Type, from: BindingType, to: List[Type], map: SubstParamsMap): Type =
+ tp match {
+ case tp: ParamType =>
+ if (tp.binder == from) to(tp.paramNum) else tp
+ case tp: NamedType =>
+ if (tp.symbol.isStatic) tp
+ else tp.derivedNamedType(substParams(tp.prefix, from, to, map))
+ case _: ThisType | NoPrefix | _: RefinedThis =>
+ tp
+ case tp: RefinedType =>
+ tp.derivedRefinedType(substParams(tp.parent, from, to, map), tp.refinedName, substParams(tp.refinedInfo, from, to, map))
+ case _ =>
+ (if (map != null) map else new SubstParamsMap(from, to))
+ .mapOver(tp)
+ }
+
private def existsStatic(syms: List[Symbol]): Boolean = syms match {
case sym :: syms1 => sym.isStatic || existsStatic(syms1)
case nil => false
}
- final class SubstBoundMap(from: BoundType, to: Type) extends TypeMap {
- def apply(tp: Type) = subst(tp, from, to, this)
- }
-
final class SubstBindingMap(from: BindingType, to: BindingType) extends TypeMap {
def apply(tp: Type) = subst(tp, from, to, this)
}
@@ -187,4 +199,12 @@ trait Substituters { this: Context =>
final class SubstRefinedThisMap(from: RefinedType, to: Type) extends TypeMap {
def apply(tp: Type): Type = substThis(tp, from, to, this)
}
+
+ final class SubstParamMap(from: ParamType, to: Type) extends TypeMap {
+ def apply(tp: Type) = substParam(tp, from, to, this)
+ }
+
+ final class SubstParamsMap(from: BindingType, to: List[Type]) extends TypeMap {
+ def apply(tp: Type) = substParams(tp, from, to, this)
+ }
} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala
index 63c148e20..e3c63b6a5 100644
--- a/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -30,6 +30,10 @@ trait SymDenotations { this: Context =>
result.validFor = stablePeriod
result
}
+
+ def lookup(name: Name): PreDenotation =
+ if (owner.isClass && (owner ne outer.owner)) owner.asClass.membersNamed(name)
+ else scope.denotsNamed(name)
}
object SymDenotations {
@@ -38,7 +42,7 @@ object SymDenotations {
*/
class SymDenotation private[SymDenotations] (
final val symbol: Symbol,
- _owner: Symbol,
+ ownerIfExists: Symbol,
final val name: Name,
initFlags: FlagSet,
initInfo: Type,
@@ -48,54 +52,54 @@ object SymDenotations {
// ------ Getting and setting fields -----------------------------
- private[this] var _flags: FlagSet = adaptFlags(initFlags)
- private[this] var _info: Type = initInfo
- private[this] var _privateWithin: Symbol = initPrivateWithin
- private[this] var _annotations: List[Annotation] = Nil
+ private[this] var myFlags: FlagSet = adaptFlags(initFlags)
+ private[this] var myInfo: Type = initInfo
+ private[this] var myPrivateWithin: Symbol = initPrivateWithin
+ private[this] var myAnnotations: List[Annotation] = Nil
/** The owner of the symbol */
- def owner: Symbol = _owner
+ def owner: Symbol = ownerIfExists
/** The flag set */
- final def flags: FlagSet = { ensureCompleted(); _flags }
+ final def flags: FlagSet = { ensureCompleted(); myFlags }
- final def flagsUNSAFE = _flags // !!! DEBUG; drop when no longer needed
+ final def flagsUNSAFE = myFlags // !!! DEBUG; drop when no longer needed
/** Adapt flag set to this denotation's term or type nature */
def adaptFlags(flags: FlagSet) = if (isType) flags.toTypeFlags else flags.toTermFlags
/** Update the flag set */
private final def flags_=(flags: FlagSet): Unit =
- _flags = adaptFlags(flags)
+ myFlags = adaptFlags(flags)
/** Set given flags(s) of this denotation */
- final def setFlag(flags: FlagSet): Unit = { _flags |= flags }
+ final def setFlag(flags: FlagSet): Unit = { myFlags |= flags }
/** UnsSet given flags(s) of this denotation */
- final def resetFlag(flags: FlagSet): Unit = { _flags &~= flags }
+ final def resetFlag(flags: FlagSet): Unit = { myFlags &~= flags }
final def is(fs: FlagSet) = {
- (if (fs <= FromStartFlags) _flags else flags) is fs
+ (if (fs <= FromStartFlags) myFlags else flags) is fs
}
final def is(fs: FlagSet, butNot: FlagSet) =
- (if (fs <= FromStartFlags && butNot <= FromStartFlags) _flags else flags) is (fs, butNot)
+ (if (fs <= FromStartFlags && butNot <= FromStartFlags) myFlags else flags) is (fs, butNot)
final def is(fs: FlagConjunction) =
- (if (fs <= FromStartFlags) _flags else flags) is fs
+ (if (fs <= FromStartFlags) myFlags else flags) is fs
final def is(fs: FlagConjunction, butNot: FlagSet) =
- (if (fs <= FromStartFlags && butNot <= FromStartFlags) _flags else flags) is (fs, butNot)
+ (if (fs <= FromStartFlags && butNot <= FromStartFlags) myFlags else flags) is (fs, butNot)
/** The type info.
* The info is an instance of TypeType iff this is a type denotation
- * Uncompleted denotations set _info to a LazyType.
+ * Uncompleted denotations set myInfo to a LazyType.
*/
- final def info: Type = _info match {
- case _info: LazyType => completeFrom(_info); info
- case _ => _info
+ final def info: Type = myInfo match {
+ case myInfo: LazyType => completeFrom(myInfo); info
+ case _ => myInfo
}
private def completeFrom(completer: LazyType): Unit = {
- if (_flags is Touched) throw new CyclicReference(this)
- _flags |= Touched
+ if (myFlags is Touched) throw new CyclicReference(this)
+ myFlags |= Touched
Context.theBase.initialCtx.debugTraceIndented(s"completing ${this.debugString}") {
completer.complete(this)
@@ -109,36 +113,36 @@ object SymDenotations {
assert(ost.isInstanceOf[TermRef], tp)
case _ =>
}
- _info = tp
+ myInfo = tp
}
/** The denotation is completed: all attributes are fully defined */
- final def isCompleted: Boolean = ! _info.isInstanceOf[LazyType]
+ final def isCompleted: Boolean = !myInfo.isInstanceOf[LazyType]
- final def isCompleting: Boolean = (_flags is Touched) && !isCompleted
+ final def isCompleting: Boolean = (myFlags is Touched) && !isCompleted
/** The completer of this denotation. @pre: Denotation is not yet completed */
- final def completer: LazyType = _info.asInstanceOf[LazyType]
+ final def completer: LazyType = myInfo.asInstanceOf[LazyType]
/** Make sure this denotation is completed */
final def ensureCompleted(): Unit = info
/** The privateWithin boundary, NoSymbol if no boundary is given.
*/
- final def privateWithin: Symbol = { ensureCompleted(); _privateWithin }
+ final def privateWithin: Symbol = { ensureCompleted(); myPrivateWithin }
/** Set privateWithin. */
protected[core] final def privateWithin_=(sym: Symbol): Unit =
- _privateWithin = sym
+ myPrivateWithin = sym
/** The annotations of this denotation */
final def annotations: List[Annotation] = {
- ensureCompleted(); _annotations
+ ensureCompleted(); myAnnotations
}
/** Update the annotations of this denotation */
private[core] final def annotations_=(annots: List[Annotation]): Unit =
- _annotations = annots
+ myAnnotations = annots
/** Does this denotation have an annotation matching the given class symbol? */
final def hasAnnotation(cls: Symbol)(implicit ctx: Context) =
@@ -146,7 +150,7 @@ object SymDenotations {
/** Add given annotation to the annotations of this denotation */
final def addAnnotation(annot: Annotation): Unit =
- annotations = annot :: _annotations
+ annotations = annot :: myAnnotations
@tailrec
private def dropOtherAnnotations(anns: List[Annotation], cls: Symbol)(implicit ctx: Context): List[Annotation] = anns match {
@@ -156,7 +160,7 @@ object SymDenotations {
/** The symbols defined in this class.
*/
- final def decls(implicit ctx: Context): Scope = _info match {
+ final def decls(implicit ctx: Context): Scope = myInfo match {
case cinfo: ClassCompleterWithDecls => cinfo.decls
case cinfo: LazyType => completeFrom(cinfo); decls // complete-once
case _ => info.decls
@@ -206,11 +210,11 @@ object SymDenotations {
/** Make denotation not exist */
final def markAbsent(): Unit =
- _info = NoType
+ myInfo = NoType
/** Is symbol known to not exist? */
final def isAbsent: Boolean =
- _info == NoType
+ myInfo == NoType
/** Is this symbol the root class or its companion object? */
final def isRoot: Boolean = name.toTermName == nme.ROOT
@@ -416,6 +420,17 @@ object SymDenotations {
def isAsConcrete(that: Symbol)(implicit ctx: Context): Boolean =
!(this is Deferred) || (that is Deferred)
+ /** Does this symbol have defined or inherited default parameters? */
+ def hasDefaultParams(implicit ctx: Context): Boolean =
+ (this is HasDefaultParams) ||
+ !(this is NoDefaultParams) && computeDefaultParams
+
+ private def computeDefaultParams(implicit ctx: Context) = {
+ val result = allOverriddenSymbols exists (_.hasDefaultParams)
+ setFlag(if (result) InheritedDefaultParams else NoDefaultParams)
+ result
+ }
+
// def isOverridable: Boolean = !!! need to enforce that classes cannot be redefined
// def isSkolem: Boolean = ???
@@ -432,14 +447,14 @@ object SymDenotations {
* the completers.
*/
/** The class implementing this module, NoSymbol if not applicable. */
- final def moduleClass: Symbol = _info match {
+ final def moduleClass: Symbol = myInfo match {
case info: TypeRefBySym if this is ModuleVal => info.fixedSym
case info: ModuleCompleter => info.mclass
case _ => NoSymbol
}
/** The module implemented by this module class, NoSymbol if not applicable. */
- final def sourceModule: Symbol = _info match {
+ final def sourceModule: Symbol = myInfo match {
case ClassInfo(_, _, _, _, selfType: TermRefBySym) if this is ModuleClass =>
selfType.fixedSym
case info: ClassCompleterWithDecls =>
diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala
index 9e68aab6d..f45e3e140 100644
--- a/src/dotty/tools/dotc/core/Symbols.scala
+++ b/src/dotty/tools/dotc/core/Symbols.scala
@@ -224,7 +224,7 @@ trait Symbols { this: Context =>
owner: Symbol,
names: List[TypeName],
flags: FlagSet,
- boundsFn: List[TypeRef] => List[Type]) = {
+ boundsFn: List[TypeRef] => List[Type]): List[TypeSymbol] = {
val tparams = names map (_ => newNakedSymbol[TypeName](NoCoord))
val bounds = boundsFn(tparams map (_.symTypeRef))
(names, tparams, bounds).zipped foreach { (name, tparam, bound) =>
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
new file mode 100644
index 000000000..479793326
--- /dev/null
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -0,0 +1,336 @@
+package dotty.tools
+package dotc
+package core
+
+import Types._, Contexts._, Symbols._, Flags._
+import collection.mutable
+import util.SimpleMap
+
+/** Provides methods to compare types.
+ * @param constraint The initial constraint which is assumed to hold for the comparisons.
+ * The constraint set is updated when undetermined type parameters
+ * in the constraint's domain are compared.
+ */
+class TypeComparer(implicit val ctx: Context) extends DotClass {
+
+ val state = ctx.typerState
+ import state.constraint
+
+ private var pendingSubTypes: mutable.Set[(Type, Type)] = null
+ private var recCount = 0
+
+ /** Add the constraint `<bounds.lo <: param <: bounds.hi>`
+ * to `constraint`.
+ * @pre `param` is in the constraint's domain
+ */
+ def addConstraint(param: PolyParam, bounds: TypeBounds): Boolean = {
+ val pt = param.binder
+ val pnum = param.paramNum
+ val oldEntries = constraint(pt)
+ val oldBounds = oldEntries(pnum).asInstanceOf[TypeBounds]
+ val newBounds = oldBounds & bounds
+ if (oldBounds ne newBounds) {
+ val newEntries = oldEntries.clone
+ newEntries(pnum) = newBounds
+ constraint = constraint.updated(pt, newEntries)
+ }
+ isSubType(newBounds.lo, newBounds.hi)
+ }
+
+ /** Solve constraint for given type parameter `param`.
+ * If `fromBelow` is true the parameter is approximated by its lower bound,
+ * otherwise it is approximated by its upper bound. However, any occurrences
+ * of the parameter in a refinement somewhere in the bound are removed.
+ * (Such occurrences can arise for F-bounded types).
+ * The type parameter is removed from the constraint's domain and all its
+ * occurrences are replaced by its approximation.
+ * @return the instantiating type
+ * @pre `param` is associated with type bounds in the current constraint.
+ */
+ def approximate(param: PolyParam, fromBelow: Boolean): Type = {
+ val removeParam = new TypeMap {
+ override def apply(tp: Type) = mapOver {
+ tp match {
+ case tp: RefinedType if param occursIn tp.refinedInfo => tp.parent
+ case _ => tp
+ }
+ }
+ }
+ val bounds = constraint(param).asInstanceOf[TypeBounds]
+ val bound = if (fromBelow) bounds.lo else bounds.hi
+ val inst = removeParam(bound)
+ constraint = constraint.replace(param, inst)
+ inst
+ }
+
+ def isSubType(tp1: Type, tp2: Type): Boolean =
+ if (tp1 == NoType || tp2 == NoType) false
+ else if (tp1 eq tp2) true
+ else {
+ val cs = constraint
+ try {
+ recCount += 1
+ val result =
+ if (recCount < LogPendingSubTypesThreshold) firstTry(tp1, tp2)
+ else monitoredIsSubType(tp1, tp2)
+ recCount -= 1
+ if (!result) constraint = cs
+ result
+ } catch {
+ case ex: Throwable =>
+ recCount -= 1
+ constraint = cs
+ throw ex
+ }
+ }
+
+ def monitoredIsSubType(tp1: Type, tp2: Type) = {
+ if (pendingSubTypes == null) {
+ pendingSubTypes = new mutable.HashSet[(Type, Type)]
+ ctx.log(s"!!! deep subtype recursion involving $tp1 <:< $tp2")
+ }
+ val p = (tp1, tp2)
+ !pendingSubTypes(p) && {
+ try {
+ pendingSubTypes += p
+ firstTry(tp1, tp2)
+ } finally {
+ pendingSubTypes -= p
+ }
+ }
+ }
+
+ def firstTry(tp1: Type, tp2: Type): Boolean = ctx.debugTraceIndented(s"$tp1 <:< $tp2") {
+ tp2 match {
+ case tp2: NamedType =>
+ tp1 match {
+ case tp1: NamedType =>
+ val sym1 = tp1.symbol
+ val sym2 = tp2.symbol
+ val pre1 = tp1.prefix
+ val pre2 = tp2.prefix
+ if (sym1 == sym2) (
+ ctx.erasedTypes
+ || sym1.isStaticOwner
+ || isSubType(pre1, pre2))
+ else (
+ tp1.name == tp2.name && isSubType(pre1, pre2)
+ || sym2.isClass && {
+ val base = tp1.baseType(sym2)
+ (base ne tp1) && isSubType(base, tp2)
+ }
+ || thirdTryNamed(tp1, tp2))
+ case _ =>
+ secondTry(tp1, tp2)
+ }
+ case WildcardType | ErrorType =>
+ true
+ case tp2: TypeVar =>
+ firstTry(tp1, tp2.thisInstance)
+ case tp2: PolyParam =>
+ constraint(tp2) match {
+ case TypeBounds(lo, _) => isSubType(tp1, lo) || addConstraint(tp2, TypeBounds.lower(tp1))
+ case _ => secondTry(tp1, tp2)
+ }
+ case _ =>
+ secondTry(tp1, tp2)
+ }
+ }
+
+ def secondTry(tp1: Type, tp2: Type): Boolean = tp1 match {
+ case WildcardType | ErrorType =>
+ true
+ case tp1: TypeVar =>
+ secondTry(tp1.thisInstance, tp2)
+ case tp1: PolyParam =>
+ constraint(tp1) match {
+ case TypeBounds(_, hi) => isSubType(hi, tp2) || addConstraint(tp1, TypeBounds.upper(tp2))
+ case _ => thirdTry(tp1, tp2)
+ }
+ case _ =>
+ thirdTry(tp1, tp2)
+ }
+
+ def thirdTryNamed(tp1: Type, tp2: NamedType): Boolean = tp2.info match {
+ case TypeBounds(lo, _) =>
+ isSubType(tp1, lo)
+ case _ =>
+ val cls2 = tp2.symbol
+ (cls2 == defn.SingletonClass && tp1.isStable
+ || cls2 == defn.NotNullClass && tp1.isNotNull
+ || (defn.hkTraits contains cls2) && isSubTypeHK(tp1, tp2)
+ || fourthTry(tp1, tp2))
+ }
+
+ def thirdTry(tp1: Type, tp2: Type): Boolean = tp2 match {
+ case tp2: NamedType =>
+ thirdTryNamed(tp1, tp2)
+ case tp2: RefinedType =>
+ isSubType(tp1, tp2.parent) &&
+ isSubType(tp1.member(tp2.refinedName).info, tp2.refinedInfo)
+ case AndType(tp21, tp22) =>
+ isSubType(tp1, tp21) && isSubType(tp1, tp22)
+ case OrType(tp21, tp22) =>
+ isSubType(tp1, tp21) || isSubType(tp1, tp22)
+ case tp2 @ MethodType(_, formals1) =>
+ tp1 match {
+ case tp1 @ MethodType(_, formals2) =>
+ tp1.signature == tp2.signature &&
+ matchingParams(formals1, formals2, tp1.isJava, tp2.isJava) &&
+ tp1.isImplicit == tp2.isImplicit && // needed?
+ isSubType(tp1.resultType, tp2.resultType.subst(tp2, tp1))
+ case _ =>
+ false
+ }
+ case tp2: PolyType =>
+ tp1 match {
+ case tp1: PolyType =>
+ tp1.signature == tp2.signature &&
+ (tp1.paramBounds corresponds tp2.paramBounds)((b1, b2) =>
+ isSameType(b1, b2.subst(tp2, tp1))) &&
+ isSubType(tp1.resultType, tp2.resultType.subst(tp2, tp1))
+ case _ =>
+ false
+ }
+ case tp2 @ ExprType(restpe1) =>
+ tp1 match {
+ case tp1 @ ExprType(restpe2) =>
+ isSubType(restpe1, restpe2)
+ case _ =>
+ false
+ }
+ case TypeBounds(lo2, hi2) =>
+ tp1 match {
+ case TypeBounds(lo1, hi1) =>
+ isSubType(lo2, lo1) && isSubType(hi1, hi2)
+ case tp1: ClassInfo =>
+ val tt = tp1.typeConstructor // was typeTemplate
+ isSubType(lo2, tt) && isSubType(tt, hi2)
+ case _ =>
+ false
+ }
+ /* needed?
+ case ClassInfo(pre2, denot2) =>
+ tp1 match {
+ case ClassInfo(pre1, denot1) =>
+ (denot1 eq denot2) && isSubType(pre2, pre1) // !!! or isSameType?
+ }
+*/
+ case _ =>
+ fourthTry(tp1, tp2)
+ }
+
+ def fourthTry(tp1: Type, tp2: Type): Boolean = tp1 match {
+ case tp1: TypeRef =>
+ ((tp1 eq defn.NothingType)
+ || (tp1 eq defn.NullType) && tp2.dealias.typeSymbol.isNonValueClass
+ || !tp1.symbol.isClass && isSubType(tp1.info.bounds.hi, tp2))
+ case tp1: SingletonType =>
+ isSubType(tp1.underlying, tp2)
+ case tp1: RefinedType =>
+ isSubType(tp1.parent, tp2)
+ case AndType(tp11, tp12) =>
+ isSubType(tp11, tp2) || isSubType(tp12, tp2)
+ case OrType(tp11, tp12) =>
+ isSubType(tp11, tp2) && isSubType(tp12, tp2)
+ case _ =>
+ false
+ }
+ /* not needed
+ def isSubArgs(tps1: List[Type], tps2: List[Type], tparams: List[TypeSymbol]): Boolean = tparams match {
+ case tparam :: tparams1 =>
+ val variance = tparam.variance
+ val t1 = tps1.head
+ val t2 = tps2.head
+ (variance > 0 || isSubType(t2, t1)) &&
+ (variance < 0 || isSubType(t1, t2)) &&
+ isSubArgs(tps1.tail, tps2.tail, tparams1)
+ case _ =>
+ assert(tps1.isEmpty && tps2.isEmpty)
+ true
+ }
+*/
+ /** Is `tp1` a subtype of a type `tp2` of the form
+ * `scala.HigerKindedXYZ { ... }?
+ * This is the case if `tp1` and `tp2` have the same number
+ * of type parameters, the bounds of tp1's paremeters
+ * are contained in the corresponding bounds of tp2's parameters
+ * and the variances of correesponding parameters agree.
+ */
+ def isSubTypeHK(tp1: Type, tp2: Type): Boolean = {
+ val tparams = tp1.typeParams
+ val hkArgs = tp2.typeArgs
+ (hkArgs.length == tparams.length) && {
+ val base = ctx.newSkolemSingleton(tp1)
+ (tparams, hkArgs).zipped.forall { (tparam, hkArg) =>
+ base.memberInfo(tparam) <:< hkArg.bounds // TODO: base.memberInfo needed?
+ } &&
+ (tparams, tp2.typeSymbol.typeParams).zipped.forall { (tparam, tparam2) =>
+ tparam.variance == tparam2.variance
+ }
+ }
+ }
+
+ /** A function implementing `tp1` matches `tp2`. */
+ final def matchesType(tp1: Type, tp2: Type, alwaysMatchSimple: Boolean): Boolean = tp1 match {
+ case tp1: MethodType =>
+ tp2 match {
+ case tp2: MethodType =>
+ tp1.isImplicit == tp2.isImplicit &&
+ matchingParams(tp1.paramTypes, tp2.paramTypes, tp1.isJava, tp2.isJava) &&
+ matchesType(tp1.resultType, tp2.resultType.subst(tp2, tp1), alwaysMatchSimple)
+ case tp2: ExprType =>
+ tp1.paramNames.isEmpty &&
+ matchesType(tp1.resultType, tp2.resultType, alwaysMatchSimple)
+ case _ =>
+ false
+ }
+ case tp1: ExprType =>
+ tp2 match {
+ case tp2: MethodType =>
+ tp2.paramNames.isEmpty &&
+ matchesType(tp1.resultType, tp2.resultType, alwaysMatchSimple)
+ case tp2: ExprType =>
+ matchesType(tp1.resultType, tp2.resultType, alwaysMatchSimple)
+ case _ =>
+ false // was: matchesType(tp1.resultType, tp2, alwaysMatchSimple)
+ }
+ case tp1: PolyType =>
+ tp2 match {
+ case tp2: PolyType =>
+ sameLength(tp1.paramNames, tp2.paramNames) &&
+ matchesType(tp1.resultType, tp2.resultType.subst(tp2, tp1), alwaysMatchSimple)
+ case _ =>
+ false
+ }
+ case _ =>
+ tp2 match {
+ case _: MethodType | _: PolyType =>
+ false
+ case tp2: ExprType =>
+ false // was: matchesType(tp1, tp2.resultType, alwaysMatchSimple)
+ case _ =>
+ alwaysMatchSimple || isSameType(tp1, tp2)
+ }
+ }
+
+ /** Are `syms1` and `syms2` parameter lists with pairwise equivalent types? */
+ private def matchingParams(formals1: List[Type], formals2: List[Type], isJava1: Boolean, isJava2: Boolean): Boolean = formals1 match {
+ case formal1 :: rest1 =>
+ formals2 match {
+ case formal2 :: rest2 =>
+ (isSameType(formal1, formal2)
+ || isJava1 && formal2 == defn.ObjectType && formal1 == defn.AnyType
+ || isJava2 && formal1 == defn.ObjectType && formal2 == defn.AnyType) && matchingParams(rest1, rest2, isJava1, isJava2)
+ case nil =>
+ false
+ }
+ case nil =>
+ formals2.isEmpty
+ }
+
+ def isSameType(tp1: Type, tp2: Type): Boolean =
+ if (tp1 == NoType || tp2 == NoType) false
+ else if (tp1 eq tp2) true
+ else isSubType(tp1, tp2) && isSubType(tp2, tp1)
+} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/core/TypeComparers.scala b/src/dotty/tools/dotc/core/TypeComparers.scala
deleted file mode 100644
index 7afeb6388..000000000
--- a/src/dotty/tools/dotc/core/TypeComparers.scala
+++ /dev/null
@@ -1,439 +0,0 @@
-package dotty.tools
-package dotc
-package core
-
-import Types._, Contexts._, Symbols._, Flags._
-import collection.mutable
-import util.SimpleMap
-
-object TypeComparers {
-
- /** Constraints over undetermined type parameters
- * @param map a map from PolyType to the type bounds that constrain the
- * polytype's type parameters. A type parameter that does not
- * have a constraint is represented by a `NoType` in the corresponding
- * array entry.
- */
- class Constraints(val map: SimpleMap[PolyType, Array[Type]]) extends AnyVal {
-
- /** Does the constraint's domain contain the type parameters of `pt`? */
- def contains(pt: PolyType): Boolean = map(pt) != null
-
- /** The constraints for given type parameter `param`, or NoType if `param` is not part of
- * the constraint domain.
- */
- def apply(param: PolyParam): Type = {
- val entries = map(param.binder)
- if (entries == null) NoType else entries(param.paramNum)
- }
-
- /** The constraints for the type parameters of `pt`.
- * @pre The polytype's type parameters are contained in the constraint's domain.
- */
- def apply(pt: PolyType): Array[Type] = map(pt)
-
- /** A new constraint which is derived from this constraint by adding or replacing
- * the entries corresponding to `pt` with `entries`.
- */
- def updated(pt: PolyType, entries: Array[Type]) =
- new Constraints(map.updated(pt, entries))
-
- /** A new constraint which is derived from this constraint by removing
- * the type parameter `param` from the domain.
- */
- def - (param: PolyParam) = {
- val pt = param.binder
- val pnum = param.paramNum
- val entries = map(pt)
- var noneLeft = true
- var i = 0
- while (noneLeft && (i < entries.length)) {
- noneLeft = (entries(i) eq NoType) || i == pnum
- i += 1
- }
- new Constraints(
- if (noneLeft) map remove pt
- else {
- val newEntries = entries.clone
- newEntries(pnum) = NoType
- map.updated(pt, newEntries)
- })
- }
-
- def + (pt: PolyType) =
- new Constraints(map.updated(pt, pt.paramBounds.toArray))
-
- /** A new constraint which is derived from this constraint by removing
- * the type parameter `param` from the domain and replacing all occurrences
- * of the parameter elsewhere in the constraint by type `tpe`.
- */
- def replace(param: PolyParam, tpe: Type)(implicit ctx: Context) = {
- def subst(entries: Array[Type]) = {
- var result = entries
- var i = 0
- while (i < entries.length) {
- entries(i) match {
- case oldBounds: TypeBounds =>
- val newBounds = oldBounds.subst(param, tpe)
- if (oldBounds ne newBounds) {
- if (result eq entries) result = entries.clone
- result(i) = newBounds
- }
- case _ =>
- }
- i += 1
- }
- result
- }
- new Constraints((this - param).map mapValues subst)
- }
- }
-
- /** Provides methods to compare types.
- * @param constraints The initial constraint which is assumed to hold for the comparisons.
- * The constraint set is updated when undetermined type parameters
- * in the constraint's domain are compared.
- */
- class TypeComparer(initConstraints: Constraints = new Constraints(SimpleMap.Empty))
- (implicit val ctx: Context) extends DotClass {
-
- private var constrs = initConstraints
-
- final def constraints = constrs
- private def constraints_=(c: Constraints) = constrs = c
-
- private var pendingSubTypes: mutable.Set[(Type, Type)] = null
- private var recCount = 0
-
- /** Add the constraint `<bounds.lo <: param <: bounds.hi>`
- * to `constraints`.
- * @pre `param` is in the constraint's domain
- */
- def addConstraint(param: PolyParam, bounds: TypeBounds): Boolean = {
- val pt = param.binder
- val pnum = param.paramNum
- val oldEntries = constraints(pt)
- val oldBounds = oldEntries(pnum).asInstanceOf[TypeBounds]
- val newBounds = oldBounds & bounds
- if (oldBounds ne newBounds) {
- val newEntries = oldEntries.clone
- newEntries(pnum) = newBounds
- constraints.updated(pt, newEntries)
- }
- isSubType(newBounds.lo, newBounds.hi)
- }
-
- /** Add all parameters in given polytype `pt` to the constraint's domain.
- * If the constraint contains already some of these parameters in its domain,
- * make a copy of the polytype and add the copy's type parameters instead.
- * Return either the original polytype, or the copy, if one was made.
- */
- def track(pt: PolyType)(implicit ctx: Context): PolyType = {
- val tracked =
- if (constraints contains pt) pt.copy(pt.paramNames, pt.paramBounds, pt.resultType)
- else pt
- constraints = constraints + tracked
- tracked
- }
-
- /** Solve constraints for given type parameter `param`.
- * If `fromBelow` is true the parameter is approximated by its lower bound,
- * otherwise it is approximated by its upper bound. However, any occurrences
- * of the parameter in a refinement somewhere in the bound are removed.
- * (Such occurrences can arise for F-bounded types).
- * The type parameter is removed from the constraint's domain and all its
- * occurrences are replaced by its approximation.
- * @return the instantiating type
- * @pre `param` is associated with type bounds in the current constraint.
- */
- def approximate(param: PolyParam, fromBelow: Boolean): Type = {
- val removeParam = new TypeMap {
- override def apply(tp: Type) = mapOver {
- tp match {
- case tp: RefinedType if param occursIn tp.refinedInfo => tp.parent
- case _ => tp
- }
- }
- }
- val bounds = constraints(param).asInstanceOf[TypeBounds]
- val bound = if (fromBelow) bounds.lo else bounds.hi
- val inst = removeParam(bound)
- constraints = constraints.replace(param, inst)
- inst
- }
-
- def isSubType(tp1: Type, tp2: Type): Boolean =
- if (tp1 == NoType || tp2 == NoType) false
- else if (tp1 eq tp2) true
- else {
- val cs = constraints
- try {
- recCount += 1
- val result =
- if (recCount < LogPendingSubTypesThreshold) firstTry(tp1, tp2)
- else monitoredIsSubType(tp1, tp2)
- recCount -= 1
- if (!result) constraints = cs
- result
- } catch {
- case ex: Throwable =>
- recCount -= 1
- constraints = cs
- throw ex
- }
- }
-
- def monitoredIsSubType(tp1: Type, tp2: Type) = {
- if (pendingSubTypes == null) {
- pendingSubTypes = new mutable.HashSet[(Type, Type)]
- ctx.log(s"!!! deep subtype recursion involving $tp1 <:< $tp2")
- }
- val p = (tp1, tp2)
- !pendingSubTypes(p) && {
- try {
- pendingSubTypes += p
- firstTry(tp1, tp2)
- } finally {
- pendingSubTypes -= p
- }
- }
- }
-
- def firstTry(tp1: Type, tp2: Type): Boolean = ctx.debugTraceIndented(s"$tp1 <:< $tp2") {
- tp2 match {
- case tp2: NamedType =>
- tp1 match {
- case tp1: NamedType =>
- val sym1 = tp1.symbol
- val sym2 = tp2.symbol
- val pre1 = tp1.prefix
- val pre2 = tp2.prefix
- if (sym1 == sym2) (
- ctx.erasedTypes
- || sym1.isStaticOwner
- || isSubType(pre1, pre2))
- else (
- tp1.name == tp2.name && isSubType(pre1, pre2)
- || sym2.isClass && {
- val base = tp1.baseType(sym2)
- (base ne tp1) && isSubType(base, tp2)
- }
- || thirdTryNamed(tp1, tp2))
- case _ =>
- secondTry(tp1, tp2)
- }
- case WildcardType | ErrorType =>
- true
- case tp2: TypeVar =>
- firstTry(tp1, tp2.thisInstance)
- case tp2: PolyParam =>
- constraints(tp2) match {
- case TypeBounds(lo, _) => isSubType(tp1, lo) || addConstraint(tp2, TypeBounds.lower(tp1))
- case _ => secondTry(tp1, tp2)
- }
- case _ =>
- secondTry(tp1, tp2)
- }
- }
-
- def secondTry(tp1: Type, tp2: Type): Boolean = tp1 match {
- case WildcardType | ErrorType =>
- true
- case tp1: TypeVar =>
- secondTry(tp1.thisInstance, tp2)
- case tp1: PolyParam =>
- constraints(tp1) match {
- case TypeBounds(_, hi) => isSubType(hi, tp2) || addConstraint(tp1, TypeBounds.upper(tp2))
- case _ => thirdTry(tp1, tp2)
- }
- case _ =>
- thirdTry(tp1, tp2)
- }
-
- def thirdTryNamed(tp1: Type, tp2: NamedType): Boolean = tp2.info match {
- case TypeBounds(lo, _) =>
- isSubType(tp1, lo)
- case _ =>
- val cls2 = tp2.symbol
- ( cls2 == defn.SingletonClass && tp1.isStable
- || cls2 == defn.NotNullClass && tp1.isNotNull
- || (defn.hkTraits contains cls2) && isSubTypeHK(tp1, tp2)
- || fourthTry(tp1, tp2)
- )
- }
-
- def thirdTry(tp1: Type, tp2: Type): Boolean = tp2 match {
- case tp2: NamedType =>
- thirdTryNamed(tp1, tp2)
- case tp2: RefinedType =>
- isSubType(tp1, tp2.parent) &&
- isSubType(tp1.member(tp2.refinedName).info, tp2.refinedInfo)
- case AndType(tp21, tp22) =>
- isSubType(tp1, tp21) && isSubType(tp1, tp22)
- case OrType(tp21, tp22) =>
- isSubType(tp1, tp21) || isSubType(tp1, tp22)
- case tp2 @ MethodType(_, formals1) =>
- tp1 match {
- case tp1 @ MethodType(_, formals2) =>
- tp1.signature == tp2.signature &&
- matchingParams(formals1, formals2, tp1.isJava, tp2.isJava) &&
- tp1.isImplicit == tp2.isImplicit && // needed?
- isSubType(tp1.resultType, tp2.resultType.subst(tp2, tp1))
- case _ =>
- false
- }
- case tp2: PolyType =>
- tp1 match {
- case tp1: PolyType =>
- tp1.signature == tp2.signature &&
- (tp1.paramBounds corresponds tp2.paramBounds)((b1, b2) =>
- isSameType(b1, b2.subst(tp2, tp1))) &&
- isSubType(tp1.resultType, tp2.resultType.subst(tp2, tp1))
- case _ =>
- false
- }
- case tp2 @ ExprType(restpe1) =>
- tp1 match {
- case tp1 @ ExprType(restpe2) =>
- isSubType(restpe1, restpe2)
- case _ =>
- false
- }
- case TypeBounds(lo2, hi2) =>
- tp1 match {
- case TypeBounds(lo1, hi1) =>
- isSubType(lo2, lo1) && isSubType(hi1, hi2)
- case tp1: ClassInfo =>
- val tt = tp1.typeConstructor // was typeTemplate
- isSubType(lo2, tt) && isSubType(tt, hi2)
- case _ =>
- false
- }
-/* needed?
- case ClassInfo(pre2, denot2) =>
- tp1 match {
- case ClassInfo(pre1, denot1) =>
- (denot1 eq denot2) && isSubType(pre2, pre1) // !!! or isSameType?
- }
-*/
- case _ =>
- fourthTry(tp1, tp2)
- }
-
- def fourthTry(tp1: Type, tp2: Type): Boolean = tp1 match {
- case tp1: TypeRef =>
- ( (tp1 eq defn.NothingType)
- || (tp1 eq defn.NullType) && tp2.dealias.typeSymbol.isNonValueClass
- || !tp1.symbol.isClass && isSubType(tp1.info.bounds.hi, tp2)
- )
- case tp1: SingletonType =>
- isSubType(tp1.underlying, tp2)
- case tp1: RefinedType =>
- isSubType(tp1.parent, tp2)
- case AndType(tp11, tp12) =>
- isSubType(tp11, tp2) || isSubType(tp12, tp2)
- case OrType(tp11, tp12) =>
- isSubType(tp11, tp2) && isSubType(tp12, tp2)
- case _ =>
- false
- }
-/* not needed
- def isSubArgs(tps1: List[Type], tps2: List[Type], tparams: List[TypeSymbol]): Boolean = tparams match {
- case tparam :: tparams1 =>
- val variance = tparam.variance
- val t1 = tps1.head
- val t2 = tps2.head
- (variance > 0 || isSubType(t2, t1)) &&
- (variance < 0 || isSubType(t1, t2)) &&
- isSubArgs(tps1.tail, tps2.tail, tparams1)
- case _ =>
- assert(tps1.isEmpty && tps2.isEmpty)
- true
- }
-*/
- /** Is `tp1` a subtype of a type `tp2` of the form
- * `scala.HigerKindedXYZ { ... }?
- * This is the case if `tp1` and `tp2` have the same number
- * of type parameters, the bounds of tp1's paremeters
- * are contained in the corresponding bounds of tp2's parameters
- * and the variances of correesponding parameters agree.
- */
- def isSubTypeHK(tp1: Type, tp2: Type): Boolean = {
- val tparams = tp1.typeParams
- val hkArgs = tp2.typeArgs
- (hkArgs.length == tparams.length) && {
- val base = ctx.newSkolemSingleton(tp1)
- (tparams, hkArgs).zipped.forall { (tparam, hkArg) =>
- base.memberInfo(tparam) <:< hkArg.bounds // TODO: base.memberInfo needed?
- } &&
- (tparams, tp2.typeSymbol.typeParams).zipped.forall { (tparam, tparam2) =>
- tparam.variance == tparam2.variance
- }
- }
- }
-
- /** A function implementing `tp1` matches `tp2`. */
- final def matchesType(tp1: Type, tp2: Type, alwaysMatchSimple: Boolean): Boolean = tp1 match {
- case tp1: MethodType =>
- tp2 match {
- case tp2: MethodType =>
- tp1.isImplicit == tp2.isImplicit &&
- matchingParams(tp1.paramTypes, tp2.paramTypes, tp1.isJava, tp2.isJava) &&
- matchesType(tp1.resultType, tp2.resultType.subst(tp2, tp1), alwaysMatchSimple)
- case tp2: ExprType =>
- tp1.paramNames.isEmpty &&
- matchesType(tp1.resultType, tp2.resultType, alwaysMatchSimple)
- case _ =>
- false
- }
- case tp1: ExprType =>
- tp2 match {
- case tp2: MethodType =>
- tp2.paramNames.isEmpty &&
- matchesType(tp1.resultType, tp2.resultType, alwaysMatchSimple)
- case tp2: ExprType =>
- matchesType(tp1.resultType, tp2.resultType, alwaysMatchSimple)
- case _ =>
- false // was: matchesType(tp1.resultType, tp2, alwaysMatchSimple)
- }
- case tp1: PolyType =>
- tp2 match {
- case tp2: PolyType =>
- sameLength(tp1.paramNames, tp2.paramNames) &&
- matchesType(tp1.resultType, tp2.resultType.subst(tp2, tp1), alwaysMatchSimple)
- case _ =>
- false
- }
- case _ =>
- tp2 match {
- case _: MethodType | _: PolyType =>
- false
- case tp2: ExprType =>
- false // was: matchesType(tp1, tp2.resultType, alwaysMatchSimple)
- case _ =>
- alwaysMatchSimple || isSameType(tp1, tp2)
- }
- }
-
- /** Are `syms1` and `syms2` parameter lists with pairwise equivalent types? */
- private def matchingParams(formals1: List[Type], formals2: List[Type], isJava1: Boolean, isJava2: Boolean): Boolean = formals1 match {
- case formal1 :: rest1 =>
- formals2 match {
- case formal2 :: rest2 =>
- ( isSameType(formal1, formal2)
- || isJava1 && formal2 == defn.ObjectType && formal1 == defn.AnyType
- || isJava2 && formal1 == defn.ObjectType && formal2 == defn.AnyType
- ) && matchingParams(rest1, rest2, isJava1, isJava2)
- case nil =>
- false
- }
- case nil =>
- formals2.isEmpty
- }
-
- def isSameType(tp1: Type, tp2: Type): Boolean =
- if (tp1 == NoType || tp2 == NoType) false
- else if (tp1 eq tp2) true
- else isSubType(tp1, tp2) && isSubType(tp2, tp1)
- }
-} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/core/TyperState.scala b/src/dotty/tools/dotc/core/TyperState.scala
new file mode 100644
index 000000000..e90070253
--- /dev/null
+++ b/src/dotty/tools/dotc/core/TyperState.scala
@@ -0,0 +1,43 @@
+package dotty.tools
+package dotc
+package core
+
+import Types._
+import Flags._
+import Contexts._
+import util.SimpleMap
+
+class TyperState extends DotClass {
+
+ /** The current constraint set */
+ def constraint: Constraint = new Constraint(SimpleMap.Empty)
+
+ /** The currently uninstantiated TypeVars */
+ def undetVars: List[TypeVar] = Nil
+
+ /** The currently outstanding errors, warnings, or infos */
+ def diagnostics: List[Diagnostic] = Nil
+
+ def constraint_=(c: Constraint): Unit = {}
+ def undetVars_=(vs: List[TypeVar]): Unit = unsupported("undetVars_=")
+ def diagnostics_=(ds: List[Diagnostic]): Unit = unsupported("diagnostics_=")
+
+ def fresh: TyperState = this
+}
+
+class MutableTyperState (previous: TyperState) extends TyperState {
+
+ private var myConstraint: Constraint = previous.constraint
+ private var myUndetVars: List[TypeVar] = previous.undetVars
+ private var myDiagnostics: List[Diagnostic] = Nil
+
+ override def constraint = myConstraint
+ override def undetVars = myUndetVars
+ override def diagnostics = myDiagnostics
+
+ override def constraint_=(c: Constraint) = myConstraint = c
+ override def undetVars_=(vs: List[TypeVar]) = myUndetVars = vs
+ override def diagnostics_=(ds: List[Diagnostic]) = myDiagnostics = ds
+
+ override def fresh: TyperState = new MutableTyperState(this)
+}
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index ce889ecd2..924517e09 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -3,7 +3,6 @@ package core
import util.HashSet
import Symbols._
-import TypeComparers._
import Flags._
import Names._
import StdNames._, NameOps._
@@ -152,6 +151,9 @@ object Types {
/** Does this type occur as a part of type `that`? */
final def occursIn(that: Type): Boolean = that.existsPart(this == _)
+ def isRepeatedParam(implicit ctx: Context): Boolean =
+ defn.RepeatedParamClasses contains typeSymbol
+
// ----- Higher-order combinators -----------------------------------
/** Returns true if there is a part of this type that satisfies predicate `p`.
@@ -547,7 +549,13 @@ object Types {
case pt: PolyType => pt.paramTypess
case _ => Nil
}
-
+/* Not sure whether we'll need this
+ final def firstParamTypes: List[Type] = this match {
+ case mt: MethodType => mt.paramTypes
+ case pt: PolyType => pt.firstParamTypes
+ case _ => Nil
+ }
+*/
/** The resultType of a PolyType, MethodType, or ExprType, the type itself for others */
def resultType: Type = this
@@ -616,10 +624,6 @@ object Types {
}
}
- /** Substitute a bound type by some other type */
- final def subst(from: BoundType, to: Type)(implicit ctx: Context): Type =
- ctx.subst(this, from, to, null)
-
/** Substitute all types of the form `PolyParam(from, N)` by
* `PolyParam(to, N)`.
*/
@@ -634,6 +638,14 @@ object Types {
final def substThis(rt: RefinedType, tp: Type)(implicit ctx: Context): Type =
ctx.substThis(this, rt, tp, null)
+ /** Substitute a bound type by some other type */
+ final def substParam(from: ParamType, to: Type)(implicit ctx: Context): Type =
+ ctx.substParam(this, from, to, null)
+
+ /** Substitute bound types by some other types */
+ final def substParams(from: BindingType, to: List[Type])(implicit ctx: Context): Type =
+ ctx.substParams(this, from, to, null)
+
/** Substitute all occurrences of symbols in `from` by references to corresponding symbols in `to`
*/
final def substSym(from: List[Symbol], to: List[Symbol])(implicit ctx: Context): Type =
@@ -1351,10 +1363,22 @@ object Types {
else MethodType(paramNames, paramTypes)(restpeExpr)
}
- def instantiate(argTypes: List[Type])(implicit ctx: Context): Type =
+ def instantiate(argTypes: => List[Type])(implicit ctx: Context): Type =
if (isDependent) new InstMethodMap(this, argTypes) apply resultType
else resultType
+ /* probably won't be needed
+ private var _isVarArgs: Boolean = _
+ private var knownVarArgs: Boolean = false
+
+ def isVarArgs(implicit ctx: Context) = {
+ if (!knownVarArgs) {
+ _isVarArgs = paramTypes.nonEmpty && paramTypes.last.isRepeatedParam
+ knownVarArgs = true
+ }
+ _isVarArgs
+ }
+*/
override def equals(that: Any) = that match {
case that: MethodType =>
this.paramNames == that.paramNames &&
@@ -1482,7 +1506,11 @@ object Types {
def copy(bt: BT): Type
}
- case class MethodParam(binder: MethodType, paramNum: Int) extends BoundType with SingletonType {
+ abstract class ParamType extends BoundType {
+ def paramNum: Int
+ }
+
+ case class MethodParam(binder: MethodType, paramNum: Int) extends ParamType with SingletonType {
type BT = MethodType
override def underlying(implicit ctx: Context): Type = binder.paramTypes(paramNum)
def copy(bt: BT) = MethodParam(bt, paramNum)
@@ -1500,7 +1528,7 @@ object Types {
override def toString = s"MethodParam(${binder.paramNames(paramNum)})"
}
- case class PolyParam(binder: PolyType, paramNum: Int) extends BoundType {
+ case class PolyParam(binder: PolyType, paramNum: Int) extends ParamType {
type BT = PolyType
def copy(bt: BT) = PolyParam(bt, paramNum)
override def underlying(implicit ctx: Context): Type = binder.paramBounds(paramNum)
diff --git a/src/dotty/tools/dotc/core/pickling/PickleBuffer.scala b/src/dotty/tools/dotc/core/pickling/PickleBuffer.scala
index e42ca58af..48aa9317e 100644
--- a/src/dotty/tools/dotc/core/pickling/PickleBuffer.scala
+++ b/src/dotty/tools/dotc/core/pickling/PickleBuffer.scala
@@ -217,7 +217,7 @@ class PickleBuffer(data: Array[Byte], from: Int, to: Int) {
STABLE -> Stable,
STATIC -> Static,
CASEACCESSOR -> CaseAccessor,
- DEFAULTPARAM -> (DefaultParam, Trait),
+ DEFAULTPARAM -> (DefaultParameterized, Trait),
BRIDGE -> Bridge,
ACCESSOR -> Accessor,
SUPERACCESSOR -> SuperAccessor,
diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
index ea42b40a4..24259211a 100644
--- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala
+++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
@@ -323,7 +323,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot:
val owner = if (atEnd) loadingMirror.RootClass else readSymbolRef()
def adjust(denot: Denotation) = {
- val denot1 = denot.disambiguate(p)
+ val denot1 = denot.disambiguate(d => p(d.symbol))
val sym = denot1.symbol
if (denot.exists && !denot1.exists) { // !!!DEBUG
val alts = denot.alternatives map (d => d+":"+d.info+"/"+d.signature)
@@ -393,7 +393,15 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot:
val nameref = readNat()
val name0 = at(nameref, readName)
val owner = readSymbolRef()
- val flags = unpickleScalaFlags(readLongNat(), name0.isTypeName)
+
+ var flags = unpickleScalaFlags(readLongNat(), name0.isTypeName)
+ if (flags is DefaultParameter) {
+ // DefaultParameterized flag now on method, not parameter
+ //assert(flags is Param, s"$name0 in $owner")
+ flags = flags &~ DefaultParameterized
+ owner.setFlag(DefaultParameterized)
+ }
+
val name = name0.adjustIfModuleClass(flags)
def isClassRoot = (name == classRoot.name) && (owner == classRoot.owner) && !(flags is ModuleClass)
diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
index dc3956fca..01d267aec 100644
--- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala
+++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
@@ -79,7 +79,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
val tycon = tp.unrefine
val cls = tycon.typeSymbol
if (cls.typeParams.length == args.length) {
- if (cls == defn.RepeatedParamClass) return toTextLocal(args.head) ~ "*"
+ if (tycon.isRepeatedParam) return toTextLocal(args.head) ~ "*"
if (cls == defn.ByNameParamClass) return "=> " ~ toText(args.head)
if (defn.FunctionClasses contains cls) return toTextFunction(args)
if (defn.TupleClasses contains cls) return toTextTuple(args)
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
new file mode 100644
index 000000000..9fdf5084c
--- /dev/null
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -0,0 +1,645 @@
+package dotty.tools
+package dotc
+package typer
+
+import core._
+import ast.{Trees, untpd, tpd, TreeInfo}
+import util.Positions._
+import Trees.Untyped
+import Contexts._
+import Types._
+import Flags._
+import Denotations._
+import NameOps._
+import Symbols._
+import Types._
+import Decorators._
+import Names._
+import StdNames._
+import Constants._
+import Inferencing._
+import collection.mutable
+import language.implicitConversions
+
+object Applications {
+
+ private val isNamedArg = (arg: Any) => arg.isInstanceOf[Trees.NamedArg[_]]
+ def hasNamedArg(args: List[Any]) = args exists isNamedArg
+}
+
+trait Applications { self: Typer =>
+
+ import Applications._
+ import Trees._
+
+ private def state(implicit ctx: Context) = ctx.typerState
+
+ def lift(defs: mutable.ListBuffer[tpd.Tree], expr: tpd.Tree, prefix: String = "")(implicit ctx: Context): tpd.Tree =
+ if (TreeInfo.isIdempotentExpr(expr)) expr
+ else {
+ val name = ctx.freshName(prefix).toTermName
+ val sym = ctx.newSymbol(ctx.owner, name, EmptyFlags, expr.tpe, coord = positionCoord(expr.pos))
+ defs += tpd.ValDef(sym, expr)
+ tpd.Ident(sym.symRef)
+ }
+
+ def liftArgs(defs: mutable.ListBuffer[tpd.Tree], methType: Type, args: List[tpd.Tree])(implicit ctx: Context) = {
+ val paramPrefixes = methType match {
+ case MethodType(paramNames, _) => paramNames map (_.toString)
+ case _ => args map (_ => "")
+ }
+ for ((arg, prefix) <- args zip paramPrefixes) yield lift(defs, arg, prefix)
+ }
+
+ def liftApp(defs: mutable.ListBuffer[tpd.Tree], tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match {
+ case Apply(fn, args) =>
+ tree.derivedApply(liftApp(defs, fn), liftArgs(defs, fn.tpe, args))
+ case TypeApply(fn, targs) =>
+ tree.derivedTypeApply(liftApp(defs, fn), targs)
+ case Select(pre, name) =>
+ tree.derivedSelect(lift(defs, pre), name)
+ case Ident(name) =>
+ lift(defs, tree)
+ case Block(stats, expr) =>
+ liftApp(defs ++= stats, expr)
+ case _ =>
+ tree
+ }
+
+ def isCompatible(tp: Type, pt: Type): Boolean = ???
+
+ /**
+ * @param Arg the type of arguments, could be tpd.Tree, untpd.Tree, or Type
+ * @param methRef the reference to the method of the application
+ * @param funType the type of the function part of the application
+ * @param args the arguments of the application
+ * @param resultType the expected result type of the application
+ */
+ abstract class Application[Arg](methRef: TermRef, funType: Type, args: List[Arg], resultType: Type)(implicit ctx: Context) {
+
+ /** The type of typed arguments: either tpd.Tree or Type */
+ type TypedArg
+
+ /** Given an original argument and the type of the corresponding formal
+ * parameter, produce a typed argument.
+ */
+ protected def typedArg(arg: Arg, formal: Type): TypedArg
+
+ /** Turn a typed tree into an argument */
+ protected def treeToArg(arg: tpd.Tree): Arg
+
+ /** Check that argument corresponds to type `formal` and
+ * possibly add it to the list of adapted arguments
+ */
+ protected def addArg(arg: TypedArg, formal: Type): Unit
+
+ /** Is this an argument of the form `expr: _*` or a RepeatedParamType
+ * derived from such an argument?
+ */
+ protected def isVarArg(arg: Arg): Boolean
+
+ /** If constructing trees, turn last `n` processed arguments into a
+ * `SeqLiteral` tree with element type `elemFormal`.
+ */
+ protected def makeVarArg(n: Int, elemFormal: Type): Unit
+
+ /** Signal failure with given message at position of given argument */
+ protected def fail(msg: => String, arg: Arg): Unit
+
+ /** Signal failure with given message at position of the application itself */
+ protected def fail(msg: => String): Unit
+
+ /** If constructing trees, the current function part, which might be
+ * affected by lifting. EmptyTree otherwise.
+ */
+ protected def normalizedFun: tpd.Tree
+
+ /** If constructing trees, pull out all parts of the function
+ * which are not idempotent into separate prefix definitions
+ */
+ protected def liftFun(): Unit = ()
+
+ /** A flag signalling that the application was so far succesful */
+ protected var ok = true
+
+ /** The function's type after widening and instantiating polytypes
+ * with polyparams or typevars in constraint set
+ */
+ val methType = funType.widen match {
+ case funType: MethodType => funType
+ case funType: PolyType => polyResult(ctx.track(funType))
+ case _ => funType
+ }
+
+ /** The arguments re-ordered so that each named argument matches the
+ * same-named formal parameter.
+ */
+ val orderedArgs =
+ if (hasNamedArg(args))
+ reorder(args.asInstanceOf[List[untpd.Tree]]).asInstanceOf[List[Arg]]
+ else
+ args
+
+ methType match {
+ case methType: MethodType =>
+ // apply the result type constraint, unless method type is dependent
+ if (!methType.isDependent)
+ ok = ok && constrainResult(methType.resultType, resultType)
+ // match all arguments with corresponding formal parameters
+ matchArgs(orderedArgs, methType.paramTypes, 0)
+ case _ =>
+ if (methType.isError) ok = false
+ else fail(s"$methString does not take parameters")
+ }
+
+ /** The application was succesful */
+ def success = ok
+
+ private def state = ctx.typerState
+
+ 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]] =
+ (for (NamedArg(name, arg1) <- args) yield (name, arg1)).toMap
+
+ def badNamedArg(arg: Tree[_ >: Untyped]): Unit = {
+ val NamedArg(name, _) = arg
+ def msg =
+ if (methodType.paramNames contains name)
+ s"parameter $name of $methString is already instantiated"
+ else
+ s"$methString does not have a parameter $name"
+ fail(msg, arg.asInstanceOf[Arg])
+ }
+
+ def recur(pnames: List[Name], args: List[Tree[T]]): List[Tree[T]] = pnames match {
+ case pname :: pnames1 =>
+ namedToArg get pname match {
+ case Some(arg) =>
+ namedToArg -= pname
+ arg :: recur(pnames1, args)
+ case None =>
+ args match {
+ case (arg @ NamedArg(aname, _)) :: args1 =>
+ if (namedToArg contains aname)
+ emptyTree[T]() :: recur(pnames1, args)
+ else {
+ badNamedArg(arg)
+ recur(pnames1, args1)
+ }
+ case arg :: args1 =>
+ arg :: recur(pnames1, args1)
+ case Nil =>
+ recur(pnames1, args)
+ }
+ }
+ case nil =>
+ if (hasNamedArg(args)) {
+ val (namedArgs, otherArgs) = args partition isNamedArg
+ namedArgs foreach badNamedArg
+ otherArgs
+ }
+ else args
+ }
+
+ recur(methodType.paramNames, args)
+ }
+
+ /** Splice new method reference into existing application */
+ def spliceMeth(meth: tpd.Tree, app: tpd.Tree): tpd.Tree = app match {
+ case Apply(fn, args) => tpd.Apply(spliceMeth(meth, fn), args)
+ case TypeApply(fn, targs) => tpd.TypeApply(spliceMeth(meth, fn), targs)
+ case _ => meth
+ }
+
+ /** Find reference to default parameter getter for parameter #n in current
+ * parameter list, or NoType if none was found
+ */
+ def findDefaultGetter(n: Int)(implicit ctx: Context): Type = {
+ def getterName = methRef.name.toTermName.defaultGetterName(n)
+ def ref(pre: Type, sym: Symbol): Type =
+ if (pre.exists && sym.isTerm) TermRef.withSym(pre, sym.asTerm) else NoType
+ val meth = methRef.symbol
+ if (meth.hasDefaultParams)
+ methRef.prefix match {
+ case NoPrefix =>
+ def findDefault(cx: Context): Type = {
+ if (cx eq NoContext) NoType
+ else if (cx.scope != cx.outer.scope &&
+ cx.lookup(methRef.name)
+ .filterWithPredicate(_.symbol == meth).exists) {
+ val denot = cx.lookup(getterName).toDenot(NoPrefix)
+ NamedType(NoPrefix, getterName).withDenot(denot)
+ } else findDefault(cx.outer)
+ }
+ findDefault(ctx)
+ case mpre =>
+ val cls = meth.owner
+ val pre =
+ if (meth.isClassConstructor) {
+ mpre.baseType(cls) match {
+ case TypeRef(clspre, _) => ref(clspre, cls.companionModule)
+ case _ => NoType
+ }
+ } else mpre
+ ref(pre, pre.member(getterName).symbol)
+ }
+ else NoType
+ }
+
+ /** Match re-ordered arguments against formal parameters
+ * @param n The position of the first parameter in formals in `methType`.
+ */
+ def matchArgs(args: List[Arg], formals: List[Type], n: Int): Unit = {
+ if (success) formals match {
+ case formal :: formals1 =>
+
+ def addTyped(arg: Arg, formal: Type) =
+ addArg(typedArg(arg, formal), formal)
+
+ def missingArg(n: Int): Unit = {
+ val pname = methodType.paramNames(n)
+ fail(
+ if (pname contains '$') s"not enough arguments for $methString"
+ else s"missing argument for parameter $pname of $methString")
+ }
+
+ def tryDefault(n: Int, args1: List[Arg]): Unit = {
+ findDefaultGetter(n + TreeInfo.numArgs(normalizedFun)) match {
+ case dref: NamedType =>
+ liftFun()
+ addTyped(treeToArg(spliceMeth(tpd.Ident(dref), normalizedFun)), formal)
+ matchArgs(args1, formals1, n + 1)
+ case _ =>
+ missingArg(n)
+ }
+ }
+
+ if (formal.isRepeatedParam)
+ args match {
+ case arg :: Nil if isVarArg(arg) =>
+ addTyped(arg, formal)
+ case _ =>
+ val elemFormal = formal.typeArgs.head
+ args foreach (addTyped(_, elemFormal))
+ makeVarArg(args.length, elemFormal)
+ }
+ else args match {
+ case EmptyTree :: args1 =>
+ tryDefault(n, args1)
+ case arg :: args1 =>
+ addTyped(arg, formal)
+ matchArgs(args1, formals1, n + 1)
+ case nil =>
+ tryDefault(n, args)
+ }
+
+ case nil =>
+ args match {
+ case arg :: args1 => fail(s"too many arguments for $methString", arg)
+ case nil =>
+ }
+ }
+ }
+
+ /** Take into account that the result type of the current method
+ * must fit the given expected result type.
+ */
+ def constrainResult(mt: Type, pt: Type): Boolean = pt match {
+ case FunProtoType(_, result) =>
+ mt match {
+ case mt: MethodType if !mt.isDependent =>
+ constrainResult(mt.resultType, pt.resultType)
+ case _ =>
+ true
+ }
+ case pt: ValueType =>
+ mt match {
+ case mt: ImplicitMethodType if !mt.isDependent =>
+ constrainResult(mt.resultType, pt)
+ case _ =>
+ isCompatible(mt, pt)
+ }
+ case _ =>
+ true
+ }
+ }
+
+ /** Subclass of Application for the cases where we are interested only
+ * in a "can/cannot apply" answer, without needing to construct trees or
+ * issue error messages.
+ */
+ abstract class TestApplication[Arg](methRef: TermRef, funType: Type, args: List[Arg], resultType: Type)(implicit ctx: Context)
+ extends Application[Arg](methRef, funType, args, resultType) {
+ type TypedArg = Arg
+ type Result = Unit
+
+ /** The type of the given argument */
+ protected def argType(arg: Arg): Type
+
+ def typedArg(arg: Arg, formal: Type): Arg = arg
+ def addArg(arg: TypedArg, formal: Type) =
+ ok = ok & isCompatible(argType(arg), formal)
+ def makeVarArg(n: Int, elemFormal: Type) = {}
+ def fail(msg: => String, arg: Arg) =
+ ok = false
+ def fail(msg: => String) =
+ ok = false
+ def normalizedFun = tpd.EmptyTree
+ }
+
+ /** Subtrait of Application for the cases where arguments are (typed or
+ * untyped) trees.
+ */
+ trait TreeApplication[T >: Untyped] extends Application[Tree[T]] {
+ type TypeArg = tpd.Tree
+ def isVarArg(arg: Tree[T]): Boolean = TreeInfo.isWildcardStarArg(arg)
+ }
+
+ /** Subclass of Application for applicability tests with trees as arguments. */
+ class ApplicableToTrees(methRef: TermRef, args: List[tpd.Tree], resultType: Type)(implicit ctx: Context)
+ extends TestApplication(methRef, methRef, args, resultType) with TreeApplication[Type] {
+ def argType(arg: tpd.Tree): Type = arg.tpe
+ def treeToArg(arg: tpd.Tree): tpd.Tree = arg
+ }
+
+ /** Subclass of Application for applicability tests with types as arguments. */
+ class ApplicableToTypes(methRef: TermRef, args: List[Type], resultType: Type)(implicit ctx: Context)
+ extends TestApplication(methRef, methRef, args, resultType) {
+ def argType(arg: Type): Type = arg
+ def treeToArg(arg: tpd.Tree): Type = arg.tpe
+ def isVarArg(arg: Type): Boolean = arg.isRepeatedParam
+ }
+
+ /** Subclass of Application for type checking an Apply node, where
+ * types of arguments are either known or unknown.
+ */
+ abstract class TypedApply[T >: Untyped](
+ app: untpd.Apply, fun: tpd.Tree, methRef: TermRef, args: List[Tree[T]], resultType: Type)(implicit ctx: Context)
+ extends Application(methRef, fun.tpe, args, resultType) with TreeApplication[T] {
+ type TypedArg = tpd.Tree
+ private var typedArgBuf = new mutable.ListBuffer[tpd.Tree]
+ private var liftedDefs: mutable.ListBuffer[tpd.Tree] = null
+ private var myNormalizedFun: tpd.Tree = fun
+
+ def addArg(arg: tpd.Tree, formal: Type): Unit =
+ typedArgBuf += adapt(arg, Mode.Expr, formal)
+
+ def makeVarArg(n: Int, elemFormal: Type): Unit = {
+ val args = typedArgBuf.takeRight(n).toList
+ typedArgBuf.trimEnd(n)
+ typedArgBuf += SeqLiteral(TypeTree(elemFormal), args)
+ }
+
+ def fail(msg: => String, arg: Tree[T]) = {
+ ctx.error(msg, arg.pos)
+ ok = false
+ }
+
+ def fail(msg: => String) = {
+ ctx.error(msg, app.pos)
+ ok = false
+ }
+
+ def normalizedFun = myNormalizedFun
+
+ override def liftFun(): Unit =
+ if (liftedDefs == null) {
+ liftedDefs = new mutable.ListBuffer[tpd.Tree]
+ 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.
+ */
+ private def firstDiff[T <: Tree[_]](xs: List[T], ys: List[T], n: Int = 0): Int = xs match {
+ case x :: xs1 =>
+ ys match {
+ case EmptyTree :: ys1 => firstDiff(xs1, ys1, n)
+ case y :: ys1 => if (x ne y) n else firstDiff(xs1, ys1, n + 1)
+ case nil => n
+ }
+ case nil =>
+ ys match {
+ case EmptyTree :: ys1 => firstDiff(xs, ys1, n)
+ case y :: ys1 => n
+ case nil => -1
+ }
+ }
+ def sameSeq[T <: Tree[_]](xs: List[T], ys: List[T]): Boolean = firstDiff(xs, ys) < 0
+
+ val result: tpd.Tree =
+ if (!success) app withType ErrorType
+ else {
+ var typedArgs = typedArgBuf.toList
+ if (!sameSeq(app.args, orderedArgs)) {
+ // need to lift arguments to maintain evaluation order in the
+ // presence of argument reorderings.
+ liftFun()
+ val eqSuffixLength = firstDiff(app.args.reverse, orderedArgs.reverse)
+ val (liftable, rest) = typedArgs splitAt (typedArgs.length - eqSuffixLength)
+ typedArgs = liftArgs(liftedDefs, methType, liftable) ++ rest
+ }
+ if (sameSeq(typedArgs, args)) // trick to cut down on tree copying
+ typedArgs = args.asInstanceOf[List[tpd.Tree]]
+ val app1 = app.withType(methodType.instantiate(typedArgs map (_.tpe)))
+ .derivedApply(normalizedFun, typedArgs)
+ if (liftedDefs != null && liftedDefs.nonEmpty) tpd.Block(liftedDefs.toList, app1)
+ else app1
+ }
+ }
+
+ /** 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 treeToArg(arg: tpd.Tree): untpd.Tree = untpd.TypedSplice(arg)
+ }
+
+ /** Subclass of Application for type checking an Apply node with typed arguments. */
+ class ApplyToTyped(app: untpd.Apply, fun: tpd.Tree, methRef: TermRef, args: List[tpd.Tree], resultType: Type)(implicit ctx: Context)
+ extends TypedApply(app, fun, methRef, args, resultType) {
+ def typedArg(arg: tpd.Tree, formal: Type): TypedArg = arg
+ def treeToArg(arg: tpd.Tree): tpd.Tree = arg
+ }
+
+ /** Is given method reference applicable to argument types `args`?
+ * @param resultType The expected result type of the application
+ */
+ def isApplicableToTrees(methRef: TermRef, args: List[tpd.Tree], resultType: Type)(implicit ctx: Context) =
+ new ApplicableToTrees(methRef, args, resultType)(ctx.fresh.withNewTyperState).success
+
+ /** Is given method reference applicable to arguments `args`?
+ * @param resultType The expected result type of the application
+ */
+ def isApplicableToTypes(methRef: TermRef, args: List[Type], resultType: Type = WildcardType)(implicit ctx: Context) =
+ new ApplicableToTypes(methRef, args, resultType)(ctx.fresh.withNewTyperState).success
+
+ /** Is `tp` a subtype of `pt`? */
+ def isSubType(tp: Type, pt: Type)(implicit ctx: Context) = (tp <:< pt)(ctx.fresh.withNewTyperState)
+
+ /** In a set of overloaded applicable alternatives, is `alt1` at least as good as
+ * `alt2`? `alt1` and `alt2` are nonoverloaded references.
+ */
+ def isAsGood(alt1: TermRef, alt2: TermRef)(implicit ctx: Context): Boolean = {
+
+ /** Is class or module class `sym1` derived from class or module class `sym2`? */
+ def isDerived(sym1: Symbol, sym2: Symbol): Boolean =
+ if (sym1 isSubClass sym2) true
+ else if (sym2 is Module) isDerived(sym1, sym2.companionClass)
+ else (sym1 is Module) && isDerived(sym1.companionClass, sym2)
+
+ /** Is alternative `alt1` with type `tp1` as specific as alternative
+ * `alt2` with type `tp2` ? This is the case if `tp2` can be applied to
+ * `tp1` or `tp2` is a supertype of `tp1`.
+ */
+ def isAsSpecific(alt1: TermRef, tp1: Type, alt2: TermRef, tp2: Type): Boolean = tp1 match {
+ case tp1: PolyType =>
+ def bounds(tparamRefs: List[TypeRef]) = tp1.paramBounds map (_.substParams(tp1, tparamRefs))
+ val tparams = ctx.newTypeParams(alt1.symbol.owner, tp1.paramNames, EmptyFlags, bounds)
+ isAsSpecific(alt1, tp1.instantiate(tparams map (_.symRef)), alt2, tp2)
+ case tp1: MethodType =>
+ isApplicableToTypes(alt2, tp1.paramTypes)
+ case _ =>
+ isSubType(tp1, tp2)
+ }
+
+ val owner1 = alt1.symbol.owner
+ val owner2 = alt2.symbol.owner
+ val tp1 = alt1.widen
+ val tp2 = alt2.widen
+
+ def winsOwner1 = isDerived(owner1, owner2)
+ def winsType1 = isAsSpecific(alt1, tp1, alt2, tp2)
+ def winsOwner2 = isDerived(owner2, owner1)
+ def winsType2 = isAsSpecific(alt2, tp2, alt1, tp1)
+
+ // Assume the following probabilities:
+ //
+ // P(winsOwnerX) = 2/3
+ // P(winsTypeX) = 1/3
+ //
+ // Then the call probabilities of the 4 basic operations are as follows:
+ //
+ // winsOwner1: 1/1
+ // winsOwner2: 1/1
+ // winsType1 : 7/9
+ // winsType2 : 4/9
+
+ if (winsOwner1) /* 6/9 */ !winsOwner2 || /* 4/9 */ winsType1 || /* 8/27 */ !winsType2
+ else if (winsOwner2) /* 2/9 */ winsType1 && /* 2/27 */ !winsType2
+ else /* 1/9 */ winsType1 || /* 2/27 */ !winsType2
+ }
+
+ /** Resolve overloaded alternative `alts`, given expected type `pt`. */
+ def resolveOverloaded(alts: List[TermRef], pt: Type)(implicit ctx: Context): List[TermRef] = {
+
+ def isDetermined(alts: List[TermRef]) = alts.isEmpty || alts.tail.isEmpty
+
+ /** The shape of given tree as a type; cannot handle named arguments. */
+ def typeShape(tree: untpd.Tree): Type = tree match {
+ case untpd.Function(args, body) =>
+ defn.FunctionType(args map Function.const(defn.AnyType), typeShape(body))
+ case _ =>
+ defn.NothingType
+ }
+
+ /** The shape of given tree as a type; is more expensive than
+ * typeShape but can can handle named arguments.
+ */
+ def treeShape(tree: untpd.Tree): tpd.Tree = tree match {
+ case NamedArg(name, arg) =>
+ val argShape = treeShape(arg)
+ tree.withType(argShape.tpe).derivedNamedArg(name, argShape)
+ case _ =>
+ Literal(Constant(null)) withType typeShape(tree)
+ }
+
+ def narrowByTypes(alts: List[TermRef], argTypes: List[Type], resultType: Type): List[TermRef] =
+ alts filter (isApplicableToTypes(_, argTypes, resultType))
+
+ def narrowMostSpecific(alts: List[TermRef]): List[TermRef] = (alts: @unchecked) match {
+ case alt :: alts1 =>
+ def winner(bestSoFar: TermRef, alts: List[TermRef]): TermRef = alts match {
+ case alt :: alts1 =>
+ winner(if (isAsGood(alt, bestSoFar)) alt else bestSoFar, alts1)
+ case nil =>
+ bestSoFar
+ }
+ val best = winner(alt, alts1)
+ def asGood(alts: List[TermRef]): List[TermRef] = alts match {
+ case alt :: alts1 =>
+ if ((alt eq best) || !isAsGood(alt, best)) asGood(alts1)
+ else alt :: asGood(alts1)
+ case nil =>
+ Nil
+ }
+ best :: asGood(alts1)
+ }
+
+ val candidates = pt match {
+ case pt @ FunProtoType(args, resultType) =>
+ val numArgs = args.length
+
+ def sizeFits(alt: TermRef, tp: Type): Boolean = tp match {
+ case tp: PolyType => sizeFits(alt, tp.resultType)
+ case MethodType(_, ptypes) =>
+ val numParams = ptypes.length
+ def isVarArgs = ptypes.nonEmpty && ptypes.last.isRepeatedParam
+ def hasDefault = alt.symbol.hasDefaultParams
+ if (numParams == numArgs) true
+ else if (numParams < numArgs) isVarArgs
+ else if (numParams > numArgs + 1) hasDefault
+ else isVarArgs || hasDefault
+ }
+
+ def narrowBySize(alts: List[TermRef]): List[TermRef] =
+ alts filter (alt => sizeFits(alt, alt.widen))
+
+ def narrowByShapes(alts: List[TermRef]): List[TermRef] =
+ if (args exists (_.isInstanceOf[untpd.Function]))
+ if (args exists (_.isInstanceOf[NamedArg[_]]))
+ narrowByTrees(alts, args map treeShape, resultType)
+ else
+ narrowByTypes(alts, args map typeShape, resultType)
+ else
+ alts
+
+ def narrowByTrees(alts: List[TermRef], args: List[tpd.Tree], resultType: Type): List[TermRef] =
+ alts filter (isApplicableToTrees(_, args, resultType))
+
+ val alts1 = narrowBySize(alts)
+ if (isDetermined(alts1)) alts1
+ else {
+ val alts2 = narrowByShapes(alts1)
+ if (isDetermined(alts2)) alts2
+ else narrowByTrees(alts2, pt.typedArgs, resultType)
+ }
+
+ case defn.FunctionType(args, resultType) =>
+ narrowByTypes(alts, args, resultType)
+
+ case tp =>
+ alts filter (isSubType(_, tp))
+ }
+
+ if (isDetermined(candidates)) candidates
+ else narrowMostSpecific(candidates)
+ }
+} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala
new file mode 100644
index 000000000..9d244ea3e
--- /dev/null
+++ b/src/dotty/tools/dotc/typer/Inferencing.scala
@@ -0,0 +1,82 @@
+package dotty.tools
+package dotc
+package typer
+
+import core._
+import Contexts._, Types._, Flags._, Denotations._, NameOps._, Symbols._
+import annotation.unchecked
+
+object Inferencing {
+
+ implicit class Infer(val ictx: Context) extends AnyVal {
+
+ implicit private def ctx = ictx
+ private def state = ctx.typerState
+
+ /** Add all parameters in given polytype `pt` to the constraint's domain.
+ * If the constraint contains already some of these parameters in its domain,
+ * make a copy of the polytype and add the copy's type parameters instead.
+ * Return either the original polytype, or the copy, if one was made.
+ */
+ def track(pt: PolyType): PolyType = {
+ val tracked =
+ if (state.constraint contains pt) pt.copy(pt.paramNames, pt.paramBounds, pt.resultType)
+ else pt
+ state.constraint = state.constraint + tracked
+ tracked
+ }
+
+ /** Interpolate undetermined variables.
+ * If a variable appears covariantly in type `tp`, approximate it by
+ * its lower bound. Otherwise, if it appears contravariantly in type `tp`,
+ * approximate it by its upper bound. Otherwise, if `always` is true,
+ * approximate it also by its lower bound.
+ * Instantiated variables are removed from `undetVars`.
+ */
+ def interpolateUndetVars(upTo: List[TypeVar], tp: Type, always: Boolean = false): Unit = {
+ def recur(undets: List[TypeVar]): List[TypeVar] =
+ if (undets eq upTo) undets
+ else (undets: @unchecked) match {
+ case tvar :: rest =>
+ def instantiate(fromBelow: Boolean) = {
+ tvar.instantiateWith(ctx.typeComparer.approximate(tvar.origin, fromBelow))
+ recur(rest)
+ }
+ val v = tp varianceOf tvar
+ if (v is Covariant) instantiate(fromBelow = true)
+ else if (v is Contravariant) instantiate(fromBelow = false)
+ else if (always) instantiate(fromBelow = true)
+ else tvar :: recur(rest)
+ }
+ state.undetVars = recur(state.undetVars)
+ }
+
+ def newTypeVars(pt: PolyType): List[TypeVar] = {
+ val tvars =
+ for (n <- (0 until pt.paramNames.length).toList)
+ yield TypeVar(PolyParam(pt, n))
+ state.undetVars = tvars ++ state.undetVars
+ tvars
+ }
+
+ def isSubTypes(actuals: List[Type], formals: List[Type])(implicit ctx: Context): Boolean = formals match {
+ case formal :: formals1 =>
+ actuals match {
+ case actual :: actuals1 => actual <:< formal && isSubTypes(actuals1, formals1)
+ case _ => false
+ }
+ case nil =>
+ actuals.isEmpty
+ }
+/* not needed right now
+ def formalParameters[T](mtp: MethodType, actuals: List[T])(isRepeated: T => Boolean)(implicit ctx: Context) =
+ if (mtp.isVarArgs && !(actuals.nonEmpty && isRepeated(actuals.last))) {
+ val leading = mtp.paramTypes.init
+ val repeated = mtp.paramTypes.last.typeArgs.head
+ val trailing = List.fill(actuals.length - leading.length)(repeated)
+ leading ++ trailing
+ }
+ else mtp.paramTypes
+ */
+ }
+} \ 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 16d643552..43589aac5 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -237,6 +237,7 @@ class Namer { typer: Typer =>
lazy val schema = paramFn(WildcardType)
val site = sym.owner.thisType
val inherited = {
+ // TODO: Look only at member of supertype instead?
((NoType: Type) /: sym.owner.info.baseClasses.tail) { (tp, cls) =>
val itpe = cls.info
.nonPrivateDecl(sym.name)
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 98f0d4d6e..853575277 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -4,8 +4,20 @@ package typer
import core._
import ast._
-import Trees._, Constants._, StdNames._, Scopes._, Denotations._
-import Contexts._, Symbols._, Types._, SymDenotations._, Names._, NameOps._, Flags._, Decorators._
+import Trees._
+import Constants._
+import StdNames._
+import Scopes._
+import Denotations._
+import Inferencing.Infer
+import Contexts._
+import Symbols._
+import Types._
+import SymDenotations._
+import Names._
+import NameOps._
+import Flags._
+import Decorators._
import util.Positions._
import util.SourcePosition
import collection.mutable
@@ -33,7 +45,7 @@ object Typer {
}
}
-class Typer extends Namer {
+class Typer extends Namer with Applications {
import tpd._
import Typer._
@@ -183,13 +195,10 @@ class Typer extends Namer {
if (ctx eq NoContext) previous
else {
val outer = ctx.outer
- val curScope = ctx.scope
- val curOwner = ctx.owner
- if (curScope ne outer.scope) {
- val defDenots =
- if (curOwner.isClass && (curOwner ne outer.owner)) curOwner.asClass.membersNamed(name)
- else curScope.denotsNamed(name)
+ if (ctx.scope ne outer.scope) {
+ val defDenots = ctx.lookup(name)
if (defDenots.exists) {
+ val curOwner = ctx.owner
val pre = curOwner.thisType
val found = NamedType(pre, name).withDenot(defDenots toDenot pre)
if (!(curOwner is Package) || isDefinedInCurrentUnit(defDenots))
@@ -234,55 +243,32 @@ class Typer extends Namer {
tree.withType(ownType).derivedSelect(qual1, tree.name)
}
- class FunProtoType(args: List[untpd.Tree], resultType: Type)(implicit ctx: Context) extends UncachedGroundType {
- private var _typedArgs: List[tpd.Tree] = null
- private var _argTypes: List[Type] = null
- def typedArgs = {
- if (_typedArgs == null)
- _typedArgs = args mapconserve (typed(_, Mode.Expr, WildcardType))
- _typedArgs
- }
- def argTypes = {
- if (_argTypes == null)
- _argTypes = typedArgs map (_.exprType)
- _argTypes
- }
- def adaptedArgs(formals: List[Type]) = {
- var fs = formals
- if (_typedArgs == null)
- _typedArgs = args mapconserve { arg =>
- val arg1 = typed(arg, Mode.Expr, fs.head)
- fs = fs.tail
- arg1
- }
- else {
- val adapted = typedArgs mapconserve { arg =>
- val arg1 = adapt(arg, Mode.Expr, fs.head)
- fs = fs.tail
- arg1
- }
- if (adapted ne typedArgs) {
- _typedArgs = adapted
- _argTypes = null
- }
- }
- typedArgs
- }
- def isApplicable(denot: SingleDenotation) = {
+ case class FunProtoType(args: List[untpd.Tree], override val resultType: Type)(implicit ctx: Context) extends UncachedGroundType {
+ private var myTypedArgs: List[tpd.Tree] = null
+
+ def argsAreTyped: Boolean = myTypedArgs != null
+ def typedArgs: List[tpd.Tree] = {
+ if (myTypedArgs == null)
+ myTypedArgs = args mapconserve (typed(_, pt = WildcardType))
+ myTypedArgs
}
}
def typedApply(tree: untpd.Apply, mode: Mode, pt: Type)(implicit ctx: Context): Tree = {
val proto = new FunProtoType(tree.args, pt)
val fun1 = typed(tree.fun, Mode.Expr, proto)
- fun1.exprType match {
- case mt @ MethodType(_, formals) =>
- val args1 = proto.adaptedArgs(formals)
- val restpe = mt.instantiate(proto.argTypes)
- tree.withType(restpe).derivedApply(fun1, args1)
- case ErrorType =>
- tree.withType(ErrorType)
+ TreeInfo.methPart(fun1).tpe match {
+ case funRef: TermRef =>
+ val app =
+ if (proto.argsAreTyped) new ApplyToTyped(tree, fun1, funRef, proto.typedArgs, pt)
+ else new ApplyToUntyped(tree, fun1, funRef, tree.args, pt)
+ app.result
+ case _ =>
+ fun1.exprType match {
+ case ErrorType =>
+ tree.withType(ErrorType)
+ }
}
}
diff --git a/src/dotty/tools/io/package.scala b/src/dotty/tools/io/package.scala
index 2543c38d2..1c0e0b5c4 100644
--- a/src/dotty/tools/io/package.scala
+++ b/src/dotty/tools/io/package.scala
@@ -21,7 +21,7 @@ package object io {
type Path = scala.reflect.io.Path
val Path = scala.reflect.io.Path
type PlainFile = scala.reflect.io.PlainFile
- val PlainFile = scala.reflect.io.PlainFile
+ //val PlainFile = scala.reflect.io.PlainFile
val Streamable = scala.reflect.io.Streamable
type VirtualDirectory = scala.reflect.io.VirtualDirectory
type VirtualFile = scala.reflect.io.VirtualFile