diff options
author | Martin Odersky <odersky@gmail.com> | 2017-03-10 19:38:39 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2017-03-14 12:05:29 +0100 |
commit | 9d0aa36c879f4bde68e01e0ba9decab21d8fce49 (patch) | |
tree | b8f4e99a9d32f3ba657c9e707d45b91923fdeed9 /compiler/src/dotty/tools/dotc/core | |
parent | 3a93b3ee128bae804044b25aa7354ce32e074678 (diff) | |
download | dotty-9d0aa36c879f4bde68e01e0ba9decab21d8fce49.tar.gz dotty-9d0aa36c879f4bde68e01e0ba9decab21d8fce49.tar.bz2 dotty-9d0aa36c879f4bde68e01e0ba9decab21d8fce49.zip |
Construct MethodTypes from parameter closure
To allow for dependencies between method type parameters, construct MethodTypes
from a closure that maps the currently constructed MethodType to its parameter types.
Diffstat (limited to 'compiler/src/dotty/tools/dotc/core')
5 files changed, 57 insertions, 46 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 99c688d50..f726cd0d1 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -308,13 +308,13 @@ object Denotations { case tp2: TypeBounds if tp2 contains tp1 => tp1 case _ => mergeConflict(tp1, tp2) } - case tp1 @ MethodType(names1, formals1) if isTerm => + case tp1: MethodType if isTerm => tp2 match { - case tp2 @ MethodType(names2, formals2) if ctx.typeComparer.matchingParams(formals1, formals2, tp1.isJava, tp2.isJava) && + case tp2: MethodType if ctx.typeComparer.matchingParams(tp1.paramTypes, tp2.paramTypes, tp1.isJava, tp2.isJava) && tp1.isImplicit == tp2.isImplicit => tp1.derivedMethodType( - mergeNames(names1, names2, nme.syntheticParamName), - formals1, + mergeNames(tp1.paramNames, tp2.paramNames, nme.syntheticParamName), + tp1.paramTypes, infoMeet(tp1.resultType, tp2.resultType.subst(tp2, tp1))) case _ => mergeConflict(tp1, tp2) @@ -471,14 +471,14 @@ object Denotations { case tp2: TypeBounds if tp2 contains tp1 => tp2 case _ => mergeConflict(tp1, tp2) } - case tp1 @ MethodType(names1, formals1) => + case tp1: MethodType => tp2 match { - case tp2 @ MethodType(names2, formals2) - if ctx.typeComparer.matchingParams(formals1, formals2, tp1.isJava, tp2.isJava) && + case tp2: MethodType + if ctx.typeComparer.matchingParams(tp1.paramTypes, tp2.paramTypes, tp1.isJava, tp2.isJava) && tp1.isImplicit == tp2.isImplicit => tp1.derivedMethodType( - mergeNames(names1, names2, nme.syntheticParamName), - formals1, tp1.resultType | tp2.resultType.subst(tp2, tp1)) + mergeNames(tp1.paramNames, tp2.paramNames, nme.syntheticParamName), + tp1.paramTypes, tp1.resultType | tp2.resultType.subst(tp2, tp1)) case _ => mergeConflict(tp1, tp2) } diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index b61fccf31..21a12dbb7 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -484,11 +484,11 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case _ => } either(isSubType(tp1, tp21), isSubType(tp1, tp22)) || fourthTry(tp1, tp2) - case tp2 @ MethodType(_, formals2) => + case tp2: MethodType => def compareMethod = tp1 match { - case tp1 @ MethodType(_, formals1) => + case tp1: MethodType => (tp1.signature consistentParams tp2.signature) && - matchingParams(formals1, formals2, tp1.isJava, tp2.isJava) && + matchingParams(tp1.paramTypes, tp2.paramTypes, tp1.isJava, tp2.isJava) && (tp1.isImplicit == tp2.isImplicit) && isSubType(tp1.resultType, tp2.resultType.subst(tp2, tp1)) case _ => @@ -503,7 +503,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { // as members of the same type. And it seems most logical to take // ()T <:< => T, since everything one can do with a => T one can // also do with a ()T by automatic () insertion. - case tp1 @ MethodType(Nil, _) => isSubType(tp1.resultType, restpe2) + case tp1 @ MethodType(Nil) => isSubType(tp1.resultType, restpe2) case _ => isSubType(tp1.widenExpr, restpe2) } compareExpr diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 2e471215b..460155f92 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -217,14 +217,14 @@ object Types { */ def isVarArgsMethod(implicit ctx: Context): Boolean = this match { case tp: PolyType => tp.resultType.isVarArgsMethod - case MethodType(_, paramTypes) => paramTypes.nonEmpty && paramTypes.last.isRepeatedParam + case mt: MethodType => mt.paramTypes.nonEmpty && mt.paramTypes.last.isRepeatedParam case _ => false } /** Is this the type of a method with a leading empty parameter list? */ def isNullaryMethod(implicit ctx: Context): Boolean = this match { - case MethodType(Nil, _) => true + case MethodType(Nil) => true case tp: PolyType => tp.resultType.isNullaryMethod case _ => false } @@ -732,7 +732,7 @@ object Types { */ final def overrides(that: Type)(implicit ctx: Context) = { def result(tp: Type): Type = tp match { - case ExprType(_) | MethodType(Nil, _) => tp.resultType + case ExprType(_) | MethodType(Nil) => tp.resultType case _ => tp } (this frozen_<:< that) || { @@ -1218,8 +1218,8 @@ object Types { * when forming the function type. */ def toFunctionType(dropLast: Int = 0)(implicit ctx: Context): Type = this match { - case mt @ MethodType(_, formals) if !mt.isDependent || ctx.mode.is(Mode.AllowDependentFunctions) => - val formals1 = if (dropLast == 0) formals else formals dropRight dropLast + case mt: MethodType if !mt.isDependent || ctx.mode.is(Mode.AllowDependentFunctions) => + val formals1 = if (dropLast == 0) mt.paramTypes else mt.paramTypes dropRight dropLast defn.FunctionOf( formals1 mapConserve (_.underlyingIfRepeated(mt.isJava)), mt.resultType, mt.isImplicit && !ctx.erasedTypes) } @@ -2312,14 +2312,16 @@ object Types { trait MethodOrPoly extends MethodicType - abstract case class MethodType(paramNames: List[TermName], paramTypes: List[Type]) - (resultTypeExp: MethodType => Type) + abstract case class MethodType(paramNames: List[TermName])( + paramTypesExp: MethodType => List[Type], + resultTypeExp: MethodType => Type) extends CachedGroundType with BindingType with TermType with MethodOrPoly with NarrowCached { thisMethodType => import MethodType._ def isJava = false def isImplicit = false + val paramTypes = paramTypesExp(this) private[core] val resType = resultTypeExp(this) assert(resType.exists) @@ -2399,10 +2401,11 @@ object Types { resType: Type = this.resType)(implicit ctx: Context) = if ((paramNames eq this.paramNames) && (paramTypes eq this.paramTypes) && (resType eq this.resType)) this else { + val paramTypesFn = (x: MethodType) => paramTypes.map(_.subst(this, x)) val resTypeFn = (x: MethodType) => resType.subst(this, x) - if (isJava) JavaMethodType(paramNames, paramTypes)(resTypeFn) - else if (isImplicit) ImplicitMethodType(paramNames, paramTypes)(resTypeFn) - else MethodType(paramNames, paramTypes)(resTypeFn) + if (isJava) JavaMethodType(paramNames)(paramTypesFn, resTypeFn) + else if (isImplicit) ImplicitMethodType(paramNames)(paramTypesFn, resTypeFn) + else MethodType(paramNames)(paramTypesFn, resTypeFn) } def instantiate(argTypes: => List[Type])(implicit ctx: Context): Type = @@ -2424,21 +2427,21 @@ object Types { override def toString = s"$prefixString($paramNames, $paramTypes, $resType)" } - final class CachedMethodType(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type) - extends MethodType(paramNames, paramTypes)(resultTypeExp) { + final class CachedMethodType(paramNames: List[TermName])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type) + extends MethodType(paramNames)(paramTypesExp, resultTypeExp) { override def equals(that: Any) = super.equals(that) && that.isInstanceOf[CachedMethodType] } - final class JavaMethodType(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type) - extends MethodType(paramNames, paramTypes)(resultTypeExp) { + final class JavaMethodType(paramNames: List[TermName])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type) + extends MethodType(paramNames)(paramTypesExp, resultTypeExp) { override def isJava = true override def equals(that: Any) = super.equals(that) && that.isInstanceOf[JavaMethodType] override def computeHash = addDelta(super.computeHash, 1) override protected def prefixString = "JavaMethodType" } - final class ImplicitMethodType(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type) - extends MethodType(paramNames, paramTypes)(resultTypeExp) { + final class ImplicitMethodType(paramNames: List[TermName])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type) + extends MethodType(paramNames)(paramTypesExp, resultTypeExp) { override def isImplicit = true override def equals(that: Any) = super.equals(that) && that.isInstanceOf[ImplicitMethodType] override def computeHash = addDelta(super.computeHash, 2) @@ -2446,7 +2449,9 @@ object Types { } abstract class MethodTypeCompanion { - def apply(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType + def apply(paramNames: List[TermName])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType + def apply(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType = + apply(paramNames)(_ => paramTypes, resultTypeExp) def apply(paramNames: List[TermName], paramTypes: List[Type], resultType: Type)(implicit ctx: Context): MethodType = apply(paramNames, paramTypes)(_ => resultType) def apply(paramTypes: List[Type])(resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType = @@ -2484,8 +2489,8 @@ object Types { } object MethodType extends MethodTypeCompanion { - def apply(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type)(implicit ctx: Context) = - unique(new CachedMethodType(paramNames, paramTypes)(resultTypeExp)) + def apply(paramNames: List[TermName])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType = + unique(new CachedMethodType(paramNames)(paramTypesExp, resultTypeExp)) private type DependencyStatus = Byte private final val Unknown: DependencyStatus = 0 // not yet computed @@ -2497,13 +2502,19 @@ object Types { } object JavaMethodType extends MethodTypeCompanion { - def apply(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type)(implicit ctx: Context) = - unique(new JavaMethodType(paramNames, paramTypes)(resultTypeExp)) + def apply(paramNames: List[TermName])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType = + unique(new JavaMethodType(paramNames)(paramTypesExp, resultTypeExp)) } object ImplicitMethodType extends MethodTypeCompanion { - def apply(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type)(implicit ctx: Context) = - unique(new ImplicitMethodType(paramNames, paramTypes)(resultTypeExp)) + def apply(paramNames: List[TermName])(paramTypesExp: MethodType => List[Type], resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType = + unique(new ImplicitMethodType(paramNames)(paramTypesExp, resultTypeExp)) + } + + /** A ternary extractor for MethodType */ + object MethodTpe { + def unapply(mt: MethodType)(implicit ctx: Context) = + Some((mt.paramNames, mt.paramTypes, mt.resultType)) } /** A by-name parameter type of the form `=> T`, or the type of a method with no parameter list. */ @@ -3660,9 +3671,9 @@ object Types { this(y, hi) } - case tp @ MethodType(pnames, ptypes) => + case tp: MethodType => variance = -variance - val y = foldOver(x, ptypes) + val y = foldOver(x, tp.paramTypes) variance = -variance this(y, tp.resultType) diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 36d478c6d..bfb4daa71 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -198,8 +198,8 @@ class ClassfileParser( */ def stripOuterParamFromConstructor() = innerClasses.get(currentClassName) match { case Some(entry) if !isStatic(entry.jflags) => - val mt @ MethodType(paramnames, paramtypes) = denot.info - denot.info = mt.derivedMethodType(paramnames.tail, paramtypes.tail, mt.resultType) + val mt @ MethodTpe(paramNames, paramTypes, resultType) = denot.info + denot.info = mt.derivedMethodType(paramNames.tail, paramTypes.tail, resultType) case _ => } @@ -207,9 +207,9 @@ class ClassfileParser( * and make constructor type polymorphic in the type parameters of the class */ def normalizeConstructorInfo() = { - val mt @ MethodType(paramnames, paramtypes) = denot.info + val mt @ MethodType(paramNames) = denot.info val rt = classRoot.typeRef appliedTo (classRoot.typeParams map (_.typeRef)) - denot.info = mt.derivedMethodType(paramnames, paramtypes, rt) + denot.info = mt.derivedMethodType(paramNames, mt.paramTypes, rt) addConstructorTypeParams(denot) } diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index faf01b177..688a2d007 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -55,8 +55,8 @@ object Scala2Unpickler { * to `RepeatedParamClass` types. */ def arrayToRepeated(tp: Type)(implicit ctx: Context): Type = tp match { - case tp @ MethodType(paramNames, paramTypes) => - val lastArg = paramTypes.last + case tp: MethodType => + val lastArg = tp.paramTypes.last assert(lastArg isRef defn.ArrayClass) val elemtp0 :: Nil = lastArg.baseArgInfos(defn.ArrayClass) val elemtp = elemtp0 match { @@ -66,8 +66,8 @@ object Scala2Unpickler { elemtp0 } tp.derivedMethodType( - paramNames, - paramTypes.init :+ defn.RepeatedParamType.appliedTo(elemtp), + tp.paramNames, + tp.paramTypes.init :+ defn.RepeatedParamType.appliedTo(elemtp), tp.resultType) case tp: PolyType => tp.derivedPolyType(tp.paramNames, tp.paramBounds, arrayToRepeated(tp.resultType)) |