diff options
Diffstat (limited to 'compiler/src')
41 files changed, 299 insertions, 206 deletions
diff --git a/compiler/src/dotty/tools/backend/jvm/CollectEntryPoints.scala b/compiler/src/dotty/tools/backend/jvm/CollectEntryPoints.scala index 0add25f3b..abcbbbb83 100644 --- a/compiler/src/dotty/tools/backend/jvm/CollectEntryPoints.scala +++ b/compiler/src/dotty/tools/backend/jvm/CollectEntryPoints.scala @@ -49,7 +49,7 @@ class CollectEntryPoints extends MiniPhaseTransform { object CollectEntryPoints{ def isJavaMainMethod(sym: Symbol)(implicit ctx: Context) = { (sym.name == nme.main) && (sym.info match { - case r@MethodType(_, List(defn.ArrayOf(t))) => + case r@MethodTpe(_, List(defn.ArrayOf(t)), _) => (t.widenDealias =:= defn.StringType) && ( r.resultType.widenDealias =:= defn.UnitType) case _ => false @@ -81,9 +81,8 @@ object CollectEntryPoints{ val possibles = if (sym.flags is Flags.Module) (toDenot(sym).info nonPrivateMember nme.main).alternatives else Nil val hasApproximate = possibles exists { m => m.info match { - case MethodType(_, p :: Nil) => - p.typeSymbol == defn.ArrayClass - case _ => false + case MethodTpe(_, p :: Nil, _) => p.typeSymbol == defn.ArrayClass + case _ => false } } // At this point it's a module with a main-looking method, so either succeed or warn that it isn't. @@ -108,8 +107,8 @@ object CollectEntryPoints{ toDenot(m.symbol).info match { case t: PolyType => fail("main methods cannot be generic.") - case t@MethodType(paramNames, paramTypes) => - if (t.resultType :: paramTypes exists (_.typeSymbol.isAbstractType)) + case MethodTpe(paramNames, paramTypes, resultType) => + if (resultType :: paramTypes exists (_.typeSymbol.isAbstractType)) fail("main methods cannot refer to type parameters or abstract types.", m.symbol.pos) else isJavaMainMethod(m.symbol) || fail("main method must have exact signature (Array[String])Unit", m.symbol.pos) diff --git a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index 51fa15706..77e979e4d 100644 --- a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -531,7 +531,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma tree match { case Apply(fun, args) => fun.tpe.widen match { - case MethodType(names, _) => + case MethodType(names) => names zip args } } diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index e5904156f..cbb256dd0 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -185,12 +185,12 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { } def valueParamss(tp: Type): (List[List[TermSymbol]], Type) = tp match { - case tp @ MethodType(paramNames, paramTypes) => + case tp: MethodType => def valueParam(name: TermName, info: Type): TermSymbol = { val maybeImplicit = if (tp.isInstanceOf[ImplicitMethodType]) Implicit else EmptyFlags ctx.newSymbol(sym, name, TermParam | maybeImplicit, info) } - val params = (paramNames, paramTypes).zipped.map(valueParam) + val params = (tp.paramNames, tp.paramTypes).zipped.map(valueParam) val (paramss, rtp) = valueParamss(tp.instantiate(params map (_.termRef))) (params :: paramss, rtp) case tp => (Nil, tp.widenExpr) @@ -607,7 +607,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { * owner to `to`, and continue until a non-weak owner is reached. */ def changeOwner(from: Symbol, to: Symbol)(implicit ctx: Context): ThisTree = { - def loop(from: Symbol, froms: List[Symbol], tos: List[Symbol]): ThisTree = { + @tailrec def loop(from: Symbol, froms: List[Symbol], tos: List[Symbol]): ThisTree = { if (from.isWeakOwner && !from.owner.isClass) loop(from.owner, from :: froms, to :: tos) else { diff --git a/compiler/src/dotty/tools/dotc/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index dc56ad8b8..903efd794 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -88,6 +88,10 @@ object Config { */ final val checkHKApplications = false + /** If this flag is set, method types are checked for valid parameter references + */ + final val checkMethodTypes = false + /** The recursion depth for showing a summarized string */ final val summarizeDepth = 2 diff --git a/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala b/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala index 59201687a..8bc18c387 100644 --- a/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala +++ b/compiler/src/dotty/tools/dotc/config/JavaPlatform.scala @@ -23,7 +23,7 @@ class JavaPlatform extends Platform { // The given symbol is a method with the right name and signature to be a runnable java program. def isJavaMainMethod(sym: SymDenotation)(implicit ctx: Context) = (sym.name == nme.main) && (sym.info match { - case t@MethodType(_, defn.ArrayOf(el) :: Nil) => el =:= defn.StringType && (t.resultType isRef defn.UnitClass) + case MethodTpe(_, defn.ArrayOf(el) :: Nil, restpe) => el =:= defn.StringType && (restpe isRef defn.UnitClass) case _ => false }) diff --git a/compiler/src/dotty/tools/dotc/config/Settings.scala b/compiler/src/dotty/tools/dotc/config/Settings.scala index 06ad2b84d..264388c03 100644 --- a/compiler/src/dotty/tools/dotc/config/Settings.scala +++ b/compiler/src/dotty/tools/dotc/config/Settings.scala @@ -5,6 +5,7 @@ import collection.mutable.{ ArrayBuffer } import scala.util.{ Try, Success, Failure } import reflect.ClassTag import core.Contexts._ +import scala.annotation.tailrec // import annotation.unchecked // Dotty deviation: Imports take precedence over definitions in enclosing package // (Note that @unchecked is in scala, not annotation, so annotation.unchecked gives @@ -216,7 +217,7 @@ object Settings { case "--" :: args => checkDependencies(stateWithArgs(skipped ++ args)) case x :: _ if x startsWith "-" => - def loop(settings: List[Setting[_]]): ArgsSummary = settings match { + @tailrec def loop(settings: List[Setting[_]]): ArgsSummary = settings match { case setting :: settings1 => val state1 = setting.tryToSet(state) if (state1 ne state) processArguments(state1, processAll, skipped) 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/Signature.scala b/compiler/src/dotty/tools/dotc/core/Signature.scala index b2e627cbe..fcd1e2376 100644 --- a/compiler/src/dotty/tools/dotc/core/Signature.scala +++ b/compiler/src/dotty/tools/dotc/core/Signature.scala @@ -4,6 +4,8 @@ package core import Names._, Types._, Contexts._, StdNames._ import TypeErasure.sigName +import scala.annotation.tailrec + /** The signature of a denotation. * Overloaded denotations with the same name are distinguished by * their signatures. A signature of a method (of type PolyType,MethodType, or ExprType) is @@ -41,7 +43,7 @@ case class Signature(paramsSig: List[TypeName], resSig: TypeName) { * equal or on of them is tpnme.Uninstantiated. */ final def consistentParams(that: Signature): Boolean = { - def loop(names1: List[TypeName], names2: List[TypeName]): Boolean = + @tailrec def loop(names1: List[TypeName], names2: List[TypeName]): Boolean = if (names1.isEmpty) names2.isEmpty else names2.nonEmpty && consistent(names1.head, names2.head) && loop(names1.tail, names2.tail) loop(this.paramsSig, that.paramsSig) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 326f0e39e..db96463e0 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1044,7 +1044,7 @@ object SymDenotations { * pre: `this.owner` is in the base class sequence of `base`. */ final def superSymbolIn(base: Symbol)(implicit ctx: Context): Symbol = { - def loop(bcs: List[ClassSymbol]): Symbol = bcs match { + @tailrec def loop(bcs: List[ClassSymbol]): Symbol = bcs match { case bc :: bcs1 => val sym = matchingDecl(bcs.head, base.thisType) .suchThat(alt => !(alt is Deferred)).symbol @@ -1060,7 +1060,7 @@ object SymDenotations { * (2) it is abstract override and its super symbol in `base` is * nonexistent or incomplete. */ - final def isIncompleteIn(base: Symbol)(implicit ctx: Context): Boolean = + @tailrec final def isIncompleteIn(base: Symbol)(implicit ctx: Context): Boolean = (this is Deferred) || (this is AbsOverride) && { val supersym = superSymbolIn(base) diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index c5e064478..33aba4d13 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -252,7 +252,7 @@ trait Symbols { this: Context => /** Create a class constructor symbol for given class `cls`. */ def newConstructor(cls: ClassSymbol, flags: FlagSet, paramNames: List[TermName], paramTypes: List[Type], privateWithin: Symbol = NoSymbol, coord: Coord = NoCoord) = - newSymbol(cls, nme.CONSTRUCTOR, flags | Method, MethodType(paramNames, paramTypes)(_ => cls.typeRef), privateWithin, coord) + newSymbol(cls, nme.CONSTRUCTOR, flags | Method, MethodType(paramNames, paramTypes, cls.typeRef), privateWithin, coord) /** Create an empty default constructor symbol for given class `cls`. */ def newDefaultConstructor(cls: ClassSymbol) = @@ -496,12 +496,15 @@ object Symbols { final def sourceFile(implicit ctx: Context): AbstractFile = { val file = associatedFile if (file != null && !file.path.endsWith("class")) file - else denot.topLevelClass.getAnnotation(defn.SourceFileAnnot) match { - case Some(sourceAnnot) => sourceAnnot.argumentConstant(0) match { - case Some(Constant(path: String)) => AbstractFile.getFile(path) + else { + val topLevelCls = denot.topLevelClass(ctx.withPhaseNoLater(ctx.flattenPhase)) + topLevelCls.getAnnotation(defn.SourceFileAnnot) match { + case Some(sourceAnnot) => sourceAnnot.argumentConstant(0) match { + case Some(Constant(path: String)) => AbstractFile.getFile(path) + case none => null + } case none => null } - case none => null } } 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/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 10587afd5..fe3396fcb 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -10,6 +10,7 @@ import dotc.transform.ExplicitOuter._ import dotc.transform.ValueClasses._ import util.DotClass import Definitions.MaxImplementedFunctionArity +import scala.annotation.tailrec /** Erased types are: * @@ -244,7 +245,7 @@ object TypeErasure { case JavaArrayType(_) => defn.ObjectType case _ => val cls2 = tp2.classSymbol - def loop(bcs: List[ClassSymbol], bestSoFar: ClassSymbol): ClassSymbol = bcs match { + @tailrec def loop(bcs: List[ClassSymbol], bestSoFar: ClassSymbol): ClassSymbol = bcs match { case bc :: bcs1 => if (cls2.derivesFrom(bc)) { val newBest = if (bestSoFar.derivesFrom(bc)) bestSoFar else bc diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 271dcda7c..abc496ec0 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -106,7 +106,7 @@ object Types { final def isValueTypeOrLambda: Boolean = isValueType || this.isInstanceOf[PolyType] /** Does this type denote a stable reference (i.e. singleton type)? */ - final def isStable(implicit ctx: Context): Boolean = stripTypeVar match { + @tailrec final def isStable(implicit ctx: Context): Boolean = stripTypeVar match { case tp: TermRef => tp.termSymbol.isStable && tp.prefix.isStable case _: SingletonType | NoPrefix => true case tp: RefinedOrRecType => tp.parent.isStable @@ -154,16 +154,16 @@ object Types { /** Is this type an instance of a non-bottom subclass of the given class `cls`? */ final def derivesFrom(cls: Symbol)(implicit ctx: Context): Boolean = { - def loop(tp: Type) = tp match { + def loop(tp: Type): Boolean = tp match { case tp: TypeRef => val sym = tp.symbol - if (sym.isClass) sym.derivesFrom(cls) else tp.superType.derivesFrom(cls) + if (sym.isClass) sym.derivesFrom(cls) else loop(tp.superType): @tailrec case tp: TypeProxy => - tp.underlying.derivesFrom(cls) + loop(tp.underlying): @tailrec case tp: AndType => - tp.tp1.derivesFrom(cls) || tp.tp2.derivesFrom(cls) + loop(tp.tp1) || loop(tp.tp2): @tailrec case tp: OrType => - tp.tp1.derivesFrom(cls) && tp.tp2.derivesFrom(cls) + loop(tp.tp1) && loop(tp.tp2): @tailrec case tp: JavaArrayType => cls == defn.ObjectClass case _ => @@ -189,7 +189,7 @@ object Types { final def isErroneous(implicit ctx: Context): Boolean = existsPart(_.isError, forceLazy = false) /** Does the type carry an annotation that is an instance of `cls`? */ - final def hasAnnotation(cls: ClassSymbol)(implicit ctx: Context): Boolean = stripTypeVar match { + @tailrec final def hasAnnotation(cls: ClassSymbol)(implicit ctx: Context): Boolean = stripTypeVar match { case AnnotatedType(tp, annot) => (annot matches cls) || (tp hasAnnotation cls) case _ => false } @@ -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 } @@ -278,7 +278,7 @@ object Types { // ----- Associated symbols ---------------------------------------------- /** The type symbol associated with the type */ - final def typeSymbol(implicit ctx: Context): Symbol = this match { + @tailrec final def typeSymbol(implicit ctx: Context): Symbol = this match { case tp: TypeRef => tp.symbol case tp: ClassInfo => tp.cls // case ThisType(cls) => cls // needed? @@ -293,16 +293,16 @@ object Types { */ final def classSymbol(implicit ctx: Context): Symbol = this match { case ConstantType(constant) => - constant.tpe.classSymbol + constant.tpe.classSymbol: @tailrec case tp: TypeRef => val sym = tp.symbol - if (sym.isClass) sym else tp.superType.classSymbol + if (sym.isClass) sym else tp.superType.classSymbol: @tailrec case tp: ClassInfo => tp.cls case tp: SingletonType => NoSymbol case tp: TypeProxy => - tp.underlying.classSymbol + tp.underlying.classSymbol: @tailrec case AndType(l, r) => val lsym = l.classSymbol val rsym = r.classSymbol @@ -326,9 +326,9 @@ object Types { tp.cls :: Nil case tp: TypeRef => val sym = tp.symbol - if (sym.isClass) sym.asClass :: Nil else tp.superType.classSymbols + if (sym.isClass) sym.asClass :: Nil else tp.superType.classSymbols: @tailrec case tp: TypeProxy => - tp.underlying.classSymbols + tp.underlying.classSymbols: @tailrec case AndType(l, r) => l.classSymbols union r.classSymbols case OrType(l, r) => @@ -338,7 +338,7 @@ object Types { } /** The term symbol associated with the type */ - final def termSymbol(implicit ctx: Context): Symbol = this match { + @tailrec final def termSymbol(implicit ctx: Context): Symbol = this match { case tp: TermRef => tp.symbol case tp: TypeProxy => tp.underlying.termSymbol case _ => NoSymbol @@ -369,11 +369,11 @@ object Types { * Defined by ClassInfo, inherited by type proxies. * Empty scope for all other types. */ - final def decls(implicit ctx: Context): Scope = this match { + @tailrec final def decls(implicit ctx: Context): Scope = this match { case tp: ClassInfo => tp.decls case tp: TypeProxy => - tp.underlying.decls + tp.underlying.decls: @tailrec case _ => EmptyScope } @@ -395,7 +395,7 @@ object Types { * name, as seen from prefix type `pre`. Declarations that have a flag * in `excluded` are omitted. */ - final def findDecl(name: Name, excluded: FlagSet)(implicit ctx: Context): Denotation = this match { + @tailrec final def findDecl(name: Name, excluded: FlagSet)(implicit ctx: Context): Denotation = this match { case tp: ClassInfo => tp.decls.denotsNamed(name).filterExcluded(excluded).toDenot(NoPrefix) case tp: TypeProxy => @@ -615,7 +615,7 @@ object Types { val ns = tp.parent.memberNames(keepOnly, pre) if (keepOnly(pre, tp.refinedName)) ns + tp.refinedName else ns case tp: TypeProxy => - tp.underlying.memberNames(keepOnly, pre) + tp.underlying.memberNames(keepOnly, pre): @tailrec case tp: AndType => tp.tp1.memberNames(keepOnly, pre) | tp.tp2.memberNames(keepOnly, pre) case tp: OrType => @@ -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) || { @@ -823,7 +823,7 @@ object Types { * def o: Outer * <o.x.type>.widen = o.C */ - final def widen(implicit ctx: Context): Type = widenSingleton match { + @tailrec final def widen(implicit ctx: Context): Type = widenSingleton match { case tp: ExprType => tp.resultType.widen case tp => tp } @@ -831,7 +831,7 @@ object Types { /** Widen from singleton type to its underlying non-singleton * base type by applying one or more `underlying` dereferences. */ - final def widenSingleton(implicit ctx: Context): Type = stripTypeVar match { + @tailrec final def widenSingleton(implicit ctx: Context): Type = stripTypeVar match { case tp: SingletonType if !tp.isOverloaded => tp.underlying.widenSingleton case _ => this } @@ -839,7 +839,7 @@ object Types { /** Widen from TermRef to its underlying non-termref * base type, while also skipping Expr types. */ - final def widenTermRefExpr(implicit ctx: Context): Type = stripTypeVar match { + @tailrec final def widenTermRefExpr(implicit ctx: Context): Type = stripTypeVar match { case tp: TermRef if !tp.isOverloaded => tp.underlying.widenExpr.widenTermRefExpr case _ => this } @@ -853,7 +853,7 @@ object Types { } /** Widen type if it is unstable (i.e. an ExprType, or TermRef to unstable symbol */ - final def widenIfUnstable(implicit ctx: Context): Type = stripTypeVar match { + @tailrec final def widenIfUnstable(implicit ctx: Context): Type = stripTypeVar match { case tp: ExprType => tp.resultType.widenIfUnstable case tp: TermRef if !tp.symbol.isStable => tp.underlying.widenIfUnstable case _ => this @@ -876,20 +876,20 @@ object Types { case tp: TypeRef => if (tp.symbol.isClass) tp else tp.info match { - case TypeAlias(tp) => tp.dealias(keepAnnots) + case TypeAlias(tp) => tp.dealias(keepAnnots): @tailrec case _ => tp } case tp: TypeVar => val tp1 = tp.instanceOpt - if (tp1.exists) tp1.dealias(keepAnnots) else tp + if (tp1.exists) tp1.dealias(keepAnnots): @tailrec else tp case tp: AnnotatedType => val tp1 = tp.tpe.dealias(keepAnnots) if (keepAnnots) tp.derivedAnnotatedType(tp1, tp.annot) else tp1 case tp: LazyRef => - tp.ref.dealias(keepAnnots) + tp.ref.dealias(keepAnnots): @tailrec case app @ HKApply(tycon, args) => val tycon1 = tycon.dealias(keepAnnots) - if (tycon1 ne tycon) app.superType.dealias(keepAnnots) + if (tycon1 ne tycon) app.superType.dealias(keepAnnots): @tailrec else this case _ => this } @@ -909,7 +909,7 @@ object Types { dealias(keepAnnots = false) /** Perform successive widenings and dealiasings until none can be applied anymore */ - final def widenDealias(implicit ctx: Context): Type = { + @tailrec final def widenDealias(implicit ctx: Context): Type = { val res = this.widen.dealias if (res eq this) res else res.widenDealias } @@ -992,7 +992,7 @@ object Types { * (*) normalizes means: follow instantiated typevars and aliases. */ def lookupRefined(name: Name)(implicit ctx: Context): Type = { - def loop(pre: Type): Type = pre.stripTypeVar match { + @tailrec def loop(pre: Type): Type = pre.stripTypeVar match { case pre: RefinedType => pre.refinedInfo match { case TypeAlias(alias) => @@ -1000,14 +1000,14 @@ object Types { case _ => loop(pre.parent) } case pre: RecType => - val candidate = loop(pre.parent) + val candidate = pre.parent.lookupRefined(name) if (candidate.exists && !pre.isReferredToBy(candidate)) { //println(s"lookupRefined ${this.toString} . $name, pre: $pre ---> $candidate / ${candidate.toString}") candidate } else NoType case SkolemType(tp) => - tp.lookupRefined(name) + loop(tp) case pre: WildcardType => WildcardType case pre: TypeRef => @@ -1047,7 +1047,7 @@ object Types { * Inherited by all other type proxies. * `NoType` for all other types. */ - final def normalizedPrefix(implicit ctx: Context): Type = this match { + @tailrec final def normalizedPrefix(implicit ctx: Context): Type = this match { case tp: NamedType => if (tp.symbol.info.isAlias) tp.info.normalizedPrefix else tp.prefix case tp: ClassInfo => @@ -1103,14 +1103,14 @@ object Types { /** The parameter types in the first parameter section of a generic type or MethodType, Empty list for others */ - final def firstParamTypes(implicit ctx: Context): List[Type] = this match { + @tailrec final def firstParamTypes(implicit ctx: Context): List[Type] = this match { case mt: MethodType => mt.paramTypes case pt: PolyType => pt.resultType.firstParamTypes case _ => Nil } /** Is this either not a method at all, or a parameterless method? */ - final def isParameterless(implicit ctx: Context): Boolean = this match { + @tailrec final def isParameterless(implicit ctx: Context): Boolean = this match { case mt: MethodType => false case pt: PolyType => pt.resultType.isParameterless case _ => true @@ -1219,8 +1219,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) } @@ -2102,7 +2102,7 @@ object Types { } object RefinedType { - def make(parent: Type, names: List[Name], infos: List[Type])(implicit ctx: Context): Type = + @tailrec def make(parent: Type, names: List[Name], infos: List[Type])(implicit ctx: Context): Type = if (names.isEmpty) parent else make(RefinedType(parent, names.head, infos.head), names.tail, infos.tail) @@ -2313,14 +2313,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) @@ -2330,7 +2332,7 @@ object Types { def apply(tp: Type) = tp match { case tp @ TypeRef(pre, name) => tp.info match { - case TypeAlias(alias) if depStatus(pre) == TrueDeps => apply(alias) + case TypeAlias(alias) if depStatus(NoDeps, pre) == TrueDeps => apply(alias) case _ => mapOver(tp) } case _ => @@ -2342,8 +2344,9 @@ object Types { else resType var myDependencyStatus: DependencyStatus = Unknown + var myParamDependencyStatus: DependencyStatus = Unknown - private def depStatus(tp: Type)(implicit ctx: Context): DependencyStatus = { + private def depStatus(initial: DependencyStatus, tp: Type)(implicit ctx: Context): DependencyStatus = { def combine(x: DependencyStatus, y: DependencyStatus) = { val status = (x & StatusMask) max (y & StatusMask) val provisional = (x | y) & Provisional @@ -2367,7 +2370,7 @@ object Types { case _ => foldOver(status, tp) } } - depStatusAcc(NoDeps, tp) + depStatusAcc(initial, tp) } /** The dependency status of this method. Some examples: @@ -2381,17 +2384,36 @@ object Types { private def dependencyStatus(implicit ctx: Context): DependencyStatus = { if (myDependencyStatus != Unknown) myDependencyStatus else { - val result = depStatus(resType) + val result = depStatus(NoDeps, resType) if ((result & Provisional) == 0) myDependencyStatus = result (result & StatusMask).toByte } } + /** The parameter dependency status of this method. Analogous to `dependencyStatus`, + * but tracking dependencies in same parameter list. + */ + private def paramDependencyStatus(implicit ctx: Context): DependencyStatus = { + if (myParamDependencyStatus != Unknown) myParamDependencyStatus + else { + val result = + if (paramTypes.isEmpty) NoDeps + else (NoDeps /: paramTypes.tail)(depStatus(_, _)) + if ((result & Provisional) == 0) myParamDependencyStatus = result + (result & StatusMask).toByte + } + } + /** Does result type contain references to parameters of this method type, * which cannot be eliminated by de-aliasing? */ def isDependent(implicit ctx: Context): Boolean = dependencyStatus == TrueDeps + /** Does one of the parameter types contain references to earlier parameters + * of this method type which cannot be eliminated by de-aliasing? + */ + def isParamDependent(implicit ctx: Context): Boolean = paramDependencyStatus == TrueDeps + protected def computeSignature(implicit ctx: Context): Signature = resultSignature.prepend(paramTypes, isJava) @@ -2400,10 +2422,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 = @@ -2425,21 +2448,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) @@ -2447,11 +2470,11 @@ 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], resultType: Type)(implicit ctx: Context): MethodType = - apply(paramNames, paramTypes)(_ => resultType) + apply(paramNames)(_ => paramTypes, _ => resultType) def apply(paramTypes: List[Type])(resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType = - apply(nme.syntheticParamNames(paramTypes.length), paramTypes)(resultTypeExp) + apply(nme.syntheticParamNames(paramTypes.length))(_ => paramTypes, resultTypeExp) def apply(paramTypes: List[Type], resultType: Type)(implicit ctx: Context): MethodType = apply(nme.syntheticParamNames(paramTypes.length), paramTypes, resultType) @@ -2474,19 +2497,31 @@ object Types { case _: ExprType => tp case _ => AnnotatedType(tp, Annotation(defn.InlineParamAnnot)) } + def integrate(tp: Type, mt: MethodType) = + tp.subst(params, (0 until params.length).toList.map(MethodParam(mt, _))) def paramInfo(param: Symbol): Type = { val paramType = translateRepeated(param.info) if (param.is(Inline)) translateInline(paramType) else paramType } - def transformResult(mt: MethodType) = - resultType.subst(params, (0 until params.length).toList map (MethodParam(mt, _))) - apply(params map (_.name.asTermName), params map paramInfo)(transformResult _) + apply(params.map(_.name.asTermName))( + mt => params.map(param => integrate(paramInfo(param), mt)), + mt => integrate(resultType, mt)) + } + + def checkValid(mt: MethodType)(implicit ctx: Context): mt.type = { + if (Config.checkMethodTypes) + for ((paramType, idx) <- mt.paramTypes.zipWithIndex) + paramType.foreachPart { + case MethodParam(`mt`, j) => assert(j < idx, mt) + case _ => + } + mt } } 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 = + checkValid(unique(new CachedMethodType(paramNames)(paramTypesExp, resultTypeExp))) private type DependencyStatus = Byte private final val Unknown: DependencyStatus = 0 // not yet computed @@ -2498,13 +2533,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 = + checkValid(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. */ @@ -2548,11 +2589,6 @@ object Types { case _ => false } - /** Is this polytype a higher-kinded type lambda as opposed to a polymorphic? - * method type? Only type lambdas get created with variances, that's how we can tell. - */ - def isTypeLambda: Boolean = variances.nonEmpty - /** PolyParam references to all type parameters of this type */ lazy val paramRefs: List[PolyParam] = paramNames.indices.toList.map(PolyParam(this, _)) @@ -2929,20 +2965,8 @@ object Types { * instantiation can be a singleton type only if the upper bound * is also a singleton type. */ - def instantiate(fromBelow: Boolean)(implicit ctx: Context): Type = { - val inst = ctx.typeComparer.instanceType(origin, fromBelow) - if (ctx.typerState.isGlobalCommittable) - inst match { - case inst: PolyParam => - assert(inst.binder.isTypeLambda, i"bad inst $this := $inst, constr = ${ctx.typerState.constraint}") - // If this fails, you might want to turn on Config.debugCheckConstraintsClosed - // to help find the root of the problem. - // Note: Parameters of type lambdas are excluded from the assertion because - // they might arise from ill-kinded code. See #1652 - case _ => - } - instantiateWith(inst) - } + def instantiate(fromBelow: Boolean)(implicit ctx: Context): Type = + instantiateWith(ctx.typeComparer.instanceType(origin, fromBelow)) /** Unwrap to instance (if instantiated) or origin (if not), until result * is no longer a TypeVar @@ -3329,6 +3353,8 @@ object Types { zeroParamClass(tp.underlying) case tp: TypeVar => zeroParamClass(tp.underlying) + case tp: HKApply => + zeroParamClass(tp.superType) case _ => NoType } @@ -3659,9 +3685,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) @@ -3684,7 +3710,7 @@ object Types { this(x, prefix) case tp @ HKApply(tycon, args) => - def foldArgs(x: T, tparams: List[TypeParamInfo], args: List[Type]): T = + @tailrec def foldArgs(x: T, tparams: List[TypeParamInfo], args: List[Type]): T = if (args.isEmpty) { assert(tparams.isEmpty) x @@ -3727,7 +3753,7 @@ object Types { case _ => x } - final def foldOver(x: T, ts: List[Type]): T = ts match { + @tailrec final def foldOver(x: T, ts: List[Type]): T = ts match { case t :: ts1 => foldOver(apply(x, t), ts1) case nil => x } diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 36d478c6d..bc140c26b 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) } @@ -339,7 +339,7 @@ class ClassfileParser( } index += 1 val restype = sig2type(tparams, skiptvs) - JavaMethodType(paramnames.toList, paramtypes.toList)(_ => restype) + JavaMethodType(paramnames.toList, paramtypes.toList, restype) case 'T' => val n = subName(';'.==).toTypeName index += 1 diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index fdb8a97ae..a9ea49ad1 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -278,8 +278,9 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle result case METHODtype => val (names, paramReader) = readNamesSkipParams - val result = MethodType(names.map(_.toTermName), paramReader.readParamTypes[Type](end))( - mt => registeringType(mt, readType())) + val result = MethodType(names.map(_.toTermName))( + mt => registeringType(mt, paramReader.readParamTypes[Type](end)), + mt => readType()) goto(end) result case PARAMtype => 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)) diff --git a/compiler/src/dotty/tools/dotc/rewrite/Rewrites.scala b/compiler/src/dotty/tools/dotc/rewrite/Rewrites.scala index c42c808fe..909a145d1 100644 --- a/compiler/src/dotty/tools/dotc/rewrite/Rewrites.scala +++ b/compiler/src/dotty/tools/dotc/rewrite/Rewrites.scala @@ -5,6 +5,7 @@ import util.{SourceFile, Positions} import Positions.Position import core.Contexts.{Context, FreshContext} import collection.mutable +import scala.annotation.tailrec /** Handles rewriting of Scala2 files to Dotty */ object Rewrites { @@ -29,7 +30,7 @@ object Rewrites { p2 } val ds = new Array[Char](cs.length + delta) - def loop(ps: List[Patch], inIdx: Int, outIdx: Int): Unit = { + @tailrec def loop(ps: List[Patch], inIdx: Int, outIdx: Int): Unit = { def copy(upTo: Int): Int = { val untouched = upTo - inIdx Array.copy(cs, inIdx, ds, outIdx, untouched) diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala index 599522b74..43202ef87 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala @@ -284,7 +284,7 @@ private class ExtractAPICollector(implicit val ctx: Context) extends ThunkHolder case pt: PolyType => assert(start == 0) paramLists(pt.resultType) - case mt @ MethodType(pnames, ptypes) => + case mt @ MethodTpe(pnames, ptypes, restpe) => // TODO: We shouldn't have to work so hard to find the default parameters // of a method, Dotty should expose a convenience method for that, see #1143 val defaults = @@ -300,7 +300,7 @@ private class ExtractAPICollector(implicit val ctx: Context) extends ThunkHolder val params = (pnames, ptypes, defaults).zipped.map((pname, ptype, isDefault) => new api.MethodParameter(pname.toString, apiType(ptype), isDefault, api.ParameterModifier.Plain)) - new api.ParameterList(params.toArray, mt.isImplicit) :: paramLists(mt.resultType, params.length) + new api.ParameterList(params.toArray, mt.isImplicit) :: paramLists(restpe, params.length) case _ => Nil } diff --git a/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala b/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala index 331fce46a..9f1e42e31 100644 --- a/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala +++ b/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala @@ -64,7 +64,7 @@ class CollectEntryPoints extends MiniPhaseTransform { val hasApproximate = possibles exists { m => m.info match { - case MethodType(_, p :: Nil) => + case MethodTpe(_, p :: Nil, _) => p.typeSymbol == defn.ArrayClass case _ => false } @@ -87,8 +87,8 @@ class CollectEntryPoints extends MiniPhaseTransform { m.symbol.info match { case t: PolyType => fail("main methods cannot be generic.") - case t@MethodType(paramNames, paramTypes) => - if (t.resultType :: paramTypes exists (_.typeSymbol.isAbstractType)) + case t: MethodType => + if (t.resultType :: t.paramTypes exists (_.typeSymbol.isAbstractType)) fail("main methods cannot refer to type parameters or abstract types.", m.symbol.pos) else javaPlatform.isJavaMainMethod(m.symbol) || fail("main method must have exact signature (Array[String])Unit", m.symbol.pos) diff --git a/compiler/src/dotty/tools/dotc/transform/ElimByName.scala b/compiler/src/dotty/tools/dotc/transform/ElimByName.scala index 0e187fc2e..59da78590 100644 --- a/compiler/src/dotty/tools/dotc/transform/ElimByName.scala +++ b/compiler/src/dotty/tools/dotc/transform/ElimByName.scala @@ -92,8 +92,8 @@ class ElimByName extends MiniPhaseTransform with InfoTransformer { thisTransform arg } - val MethodType(_, formals) = tree.fun.tpe.widen - val args1 = tree.args.zipWithConserve(formals)(transformArg) + val mt @ MethodType(_) = tree.fun.tpe.widen + val args1 = tree.args.zipWithConserve(mt.paramTypes)(transformArg) cpy.Apply(tree)(tree.fun, args1) } diff --git a/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala b/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala index d955628e3..ae3259509 100644 --- a/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala +++ b/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala @@ -48,8 +48,8 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer with Annotati private def overridesJava(sym: Symbol)(implicit ctx: Context) = sym.allOverriddenSymbols.exists(_ is JavaDefined) private def elimRepeated(tp: Type)(implicit ctx: Context): Type = tp.stripTypeVar match { - case tp @ MethodType(paramNames, paramTypes) => - val resultType1 = elimRepeated(tp.resultType) + case tp @ MethodTpe(paramNames, paramTypes, resultType) => + val resultType1 = elimRepeated(resultType) val paramTypes1 = if (paramTypes.nonEmpty && paramTypes.last.isRepeatedParam) { val last = paramTypes.last.underlyingIfRepeated(tp.isJava) diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index 3857b405f..f9c7a8e1e 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -40,8 +40,8 @@ class Erasure extends Phase with DenotTransformer { thisTransformer => def isCompacted(sym: Symbol) = sym.isAnonymousFunction && { sym.info(ctx.withPhase(ctx.phase.next)) match { - case MethodType(nme.ALLARGS :: Nil, _) => true - case _ => false + case MethodType(nme.ALLARGS :: Nil) => true + case _ => false } } @@ -269,7 +269,7 @@ object Erasure extends TypeTestsCasts{ def adaptToType(tree: Tree, pt: Type)(implicit ctx: Context): Tree = if (pt.isInstanceOf[FunProto]) tree else tree.tpe.widen match { - case MethodType(Nil, _) if tree.isTerm => + case MethodType(Nil) if tree.isTerm => adaptToType(tree.appliedToNone, pt) case tpw => if (pt.isInstanceOf[ProtoType] || tree.tpe <:< pt) @@ -697,9 +697,10 @@ object Erasure extends TypeTestsCasts{ val rhs = paramss.foldLeft(sel)((fun, vparams) => fun.tpe.widen match { - case MethodType(names, types) => Apply(fun, (vparams, types).zipped.map(adapt(_, _, untpd.EmptyTree))) - case a => error(s"can not resolve apply type $a") - + case mt: MethodType => + Apply(fun, (vparams, mt.paramTypes).zipped.map(adapt(_, _, untpd.EmptyTree))) + case a => + error(s"can not resolve apply type $a") }) adapt(rhs, resultType) }) diff --git a/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala b/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala index 91399f91a..7b15b7e54 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala @@ -53,7 +53,7 @@ class ExpandSAMs extends MiniPhaseTransform { thisTransformer => val applyRhs: Tree = applyDef.rhs val applyFn = applyDef.symbol.asTerm - val MethodType(paramNames, paramTypes) = applyFn.info + val MethodTpe(paramNames, paramTypes, _) = applyFn.info val isDefinedAtFn = applyFn.copy( name = nme.isDefinedAt, flags = Synthetic | Method, diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala index d75c32fcc..f17808e62 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -16,7 +16,9 @@ import SymUtils._ import dotty.tools.dotc.ast.tpd import dotty.tools.dotc.core.Phases.Phase import util.Property + import collection.mutable +import scala.annotation.tailrec /** This phase adds outer accessors to classes and traits that need them. * Compared to Scala 2.x, it tries to minimize the set of classes @@ -328,9 +330,9 @@ object ExplicitOuter { /** If `cls` has an outer parameter add one to the method type `tp`. */ def addParam(cls: ClassSymbol, tp: Type): Type = if (hasOuterParam(cls)) { - val mt @ MethodType(pnames, ptypes) = tp + val mt @ MethodTpe(pnames, ptypes, restpe) = tp mt.derivedMethodType( - nme.OUTER :: pnames, cls.owner.enclosingClass.typeRef :: ptypes, mt.resultType) + nme.OUTER :: pnames, cls.owner.enclosingClass.typeRef :: ptypes, restpe) } else tp /** If function in an apply node is a constructor that needs to be passed an @@ -367,7 +369,7 @@ object ExplicitOuter { def path(start: Tree = This(ctx.owner.lexicallyEnclosingClass.asClass), toCls: Symbol = NoSymbol, count: Int = -1): Tree = try { - def loop(tree: Tree, count: Int): Tree = { + @tailrec def loop(tree: Tree, count: Int): Tree = { val treeCls = tree.tpe.widen.classSymbol val outerAccessorCtx = ctx.withPhaseNoLater(ctx.lambdaLiftPhase) // lambdalift mangles local class names, which means we cannot reliably find outer acessors anymore ctx.log(i"outer to $toCls of $tree: ${tree.tpe}, looking for ${outerAccName(treeCls.asClass)(outerAccessorCtx)} in $treeCls") @@ -389,7 +391,7 @@ object ExplicitOuter { /** The outer parameter definition of a constructor if it needs one */ def paramDefs(constr: Symbol): List[ValDef] = if (constr.isConstructor && hasOuterParam(constr.owner.asClass)) { - val MethodType(outerName :: _, outerType :: _) = constr.info + val MethodTpe(outerName :: _, outerType :: _, _) = constr.info val outerSym = ctx.newSymbol(constr, outerName, Param, outerType) ValDef(outerSym) :: Nil } diff --git a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala index 597146514..8328e43de 100644 --- a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala +++ b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala @@ -29,8 +29,11 @@ import StdNames._ * - eliminates some kinds of trees: Imports, NamedArgs * - stubs out native methods * - eliminates self tree in Template and self symbol in ClassInfo - * - collapsess all type trees to trees of class TypeTree + * - collapses all type trees to trees of class TypeTree * - converts idempotent expressions with constant types + * - drops branches of ifs using the rules + * if (true) A else B --> A + * if (false) A else B --> B */ class FirstTransform extends MiniPhaseTransform with InfoTransformer with AnnotationTransformer { thisTransformer => import ast.tpd._ @@ -148,7 +151,7 @@ class FirstTransform extends MiniPhaseTransform with InfoTransformer with Annota override def transformTemplate(impl: Template)(implicit ctx: Context, info: TransformerInfo): Tree = { cpy.Template(impl)(self = EmptyValDef) } - + override def transformDefDef(ddef: DefDef)(implicit ctx: Context, info: TransformerInfo) = { if (ddef.symbol.hasAnnotation(defn.NativeAnnot)) { ddef.symbol.resetFlag(Deferred) @@ -168,13 +171,13 @@ class FirstTransform extends MiniPhaseTransform with InfoTransformer with Annota } override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo) = - if (tree.isType) TypeTree(tree.tpe).withPos(tree.pos) + if (tree.isType) TypeTree(tree.tpe).withPos(tree.pos) else constToLiteral(tree) override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo) = - if (tree.isType) TypeTree(tree.tpe).withPos(tree.pos) + if (tree.isType) TypeTree(tree.tpe).withPos(tree.pos) else constToLiteral(tree) - + override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo) = constToLiteral(tree) @@ -183,10 +186,16 @@ class FirstTransform extends MiniPhaseTransform with InfoTransformer with Annota override def transformTyped(tree: Typed)(implicit ctx: Context, info: TransformerInfo) = constToLiteral(tree) - + override def transformBlock(tree: Block)(implicit ctx: Context, info: TransformerInfo) = constToLiteral(tree) + override def transformIf(tree: If)(implicit ctx: Context, info: TransformerInfo) = + tree.cond match { + case Literal(Constant(c: Boolean)) => if (c) tree.thenp else tree.elsep + case _ => tree + } + // invariants: all modules have companion objects // all types are TypeTrees // all this types are explicit diff --git a/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala b/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala index 5609817d8..0cb453b4c 100644 --- a/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala +++ b/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala @@ -105,8 +105,9 @@ trait FullParameterization { def resultType(mapClassParams: Type => Type) = { val thisParamType = mapClassParams(clazz.classInfo.selfType) val firstArgType = if (liftThisType) thisParamType & clazz.thisType else thisParamType - MethodType(nme.SELF :: Nil, firstArgType :: Nil)(mt => - mapClassParams(origResult).substThisUnlessStatic(clazz, MethodParam(mt, 0))) + MethodType(nme.SELF :: Nil)( + mt => firstArgType :: Nil, + mt => mapClassParams(origResult).substThisUnlessStatic(clazz, MethodParam(mt, 0))) } /** Replace class type parameters by the added type parameters of the polytype `pt` */ @@ -252,10 +253,10 @@ object FullParameterization { def memberSignature(info: Type)(implicit ctx: Context): Signature = info match { case info: PolyType => memberSignature(info.resultType) - case info @ MethodType(nme.SELF :: Nil, _) => - info.resultType.ensureMethodic.signature - case info @ MethodType(nme.SELF :: otherNames, thisType :: otherTypes) => - info.derivedMethodType(otherNames, otherTypes, info.resultType).signature + case MethodTpe(nme.SELF :: Nil, _, restpe) => + restpe.ensureMethodic.signature + case info @ MethodTpe(nme.SELF :: otherNames, thisType :: otherTypes, restpe) => + info.derivedMethodType(otherNames, otherTypes, restpe).signature case _ => Signature.NotAMethod } diff --git a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala index b603a53dc..7578b57f1 100644 --- a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala +++ b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala @@ -352,12 +352,12 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform } private def liftedInfo(local: Symbol)(implicit ctx: Context): Type = local.info match { - case mt @ MethodType(pnames, ptypes) => + case MethodTpe(pnames, ptypes, restpe) => val ps = proxies(local) MethodType( ps.map(_.name.asTermName) ++ pnames, ps.map(_.info) ++ ptypes, - mt.resultType) + restpe) case info => info } diff --git a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala index a6ac71286..2035fb04b 100644 --- a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala +++ b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala @@ -139,7 +139,7 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer { val holderSymbol = ctx.newSymbol(x.symbol.owner, holderName, containerFlags, holderImpl.typeRef, coord = x.pos) val initSymbol = ctx.newSymbol(x.symbol.owner, initName, initFlags, MethodType(Nil, tpe), coord = x.pos) - val result = ref(holderSymbol).select(lazyNme.value) + val result = ref(holderSymbol).select(lazyNme.value).withPos(x.pos) val flag = ref(holderSymbol).select(lazyNme.initialized) val initer = valueInitter.changeOwnerAfter(x.symbol, initSymbol, this) val initBody = diff --git a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala index a72e10681..859ac8b06 100644 --- a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala +++ b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala @@ -27,7 +27,7 @@ class ParamForwarding(thisTransformer: DenotTransformer) { val (superArgs, superParamNames) = impl.parents match { case superCall @ Apply(fn, args) :: _ => fn.tpe.widen match { - case MethodType(paramNames, _) => (args, paramNames) + case MethodType(paramNames) => (args, paramNames) case _ => (Nil, Nil) } case _ => (Nil, Nil) diff --git a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala index 05305575e..105f54d3a 100644 --- a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala @@ -12,7 +12,9 @@ import StdNames._ import NameOps._ import Flags._ import Annotations._ + import language.implicitConversions +import scala.annotation.tailrec object SymUtils { implicit def decorateSymbol(sym: Symbol): SymUtils = new SymUtils(sym) @@ -59,14 +61,14 @@ class SymUtils(val self: Symbol) extends AnyVal { } /** The closest enclosing method or class of this symbol */ - final def enclosingMethodOrClass(implicit ctx: Context): Symbol = + @tailrec final def enclosingMethodOrClass(implicit ctx: Context): Symbol = if (self.is(Method, butNot = Label) || self.isClass) self else if (self.exists) self.owner.enclosingMethodOrClass else NoSymbol /** Apply symbol/symbol substitution to this symbol */ def subst(from: List[Symbol], to: List[Symbol]): Symbol = { - def loop(from: List[Symbol], to: List[Symbol]): Symbol = + @tailrec def loop(from: List[Symbol], to: List[Symbol]): Symbol = if (from.isEmpty) self else if (self eq from.head) to.head else loop(from.tail, to.tail) diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index a65ef00cc..5dcf16b62 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -178,6 +178,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic => */ protected def normalizedFun: Tree + protected def typeOfArg(arg: Arg): Type + /** If constructing trees, pull out all parts of the function * which are not idempotent into separate prefix definitions */ @@ -380,8 +382,16 @@ trait Applications extends Compatibility { self: Typer with Dynamic => if (success) formals match { case formal :: formals1 => - def addTyped(arg: Arg, formal: Type) = + /** Add result of typing argument `arg` against parameter type `formal`. + * @return A type transformation to apply to all arguments following this one. + */ + def addTyped(arg: Arg, formal: Type): Type => Type = { addArg(typedArg(arg, formal), formal) + if (methodType.isParamDependent) + _.substParam(MethodParam(methodType, n), typeOfArg(arg)) + else + identity + } def missingArg(n: Int): Unit = { val pname = methodType.paramNames(n) @@ -395,8 +405,10 @@ trait Applications extends Compatibility { self: Typer with Dynamic => val getter = findDefaultGetter(n + numArgs(normalizedFun)) if (getter.isEmpty) missingArg(n) else { - addTyped(treeToArg(spliceMeth(getter withPos normalizedFun.pos, normalizedFun)), formal) - matchArgs(args1, formals1, n + 1) + val substParam = addTyped( + treeToArg(spliceMeth(getter withPos normalizedFun.pos, normalizedFun)), + formal) + matchArgs(args1, formals1.mapconserve(substParam), n + 1) } } @@ -420,8 +432,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic => case EmptyTree :: args1 => tryDefault(n, args1) case arg :: args1 => - addTyped(arg, formal) - matchArgs(args1, formals1, n + 1) + val substParam = addTyped(arg, formal) + matchArgs(args1, formals1.mapconserve(substParam), n + 1) case nil => tryDefault(n, args) } @@ -477,6 +489,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => def argType(arg: Tree, formal: Type): Type = normalize(arg.tpe, formal) def treeToArg(arg: Tree): Tree = arg def isVarArg(arg: Tree): Boolean = tpd.isWildcardStarArg(arg) + def typeOfArg(arg: Tree): Type = arg.tpe def harmonizeArgs(args: List[Tree]) = harmonize(args) } @@ -494,6 +507,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => def argType(arg: Type, formal: Type): Type = arg def treeToArg(arg: Tree): Type = arg.tpe def isVarArg(arg: Type): Boolean = arg.isRepeatedParam + def typeOfArg(arg: Type): Type = arg def harmonizeArgs(args: List[Type]) = harmonizeTypes(args) } @@ -592,6 +606,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => extends TypedApply(app, fun, methRef, proto.args, resultType) { def typedArg(arg: untpd.Tree, formal: Type): TypedArg = proto.typedArg(arg, formal.widenExpr) def treeToArg(arg: Tree): untpd.Tree = untpd.TypedSplice(arg) + def typeOfArg(arg: untpd.Tree) = proto.typeOfArg(arg) } /** Subclass of Application for type checking an Apply node with typed arguments. */ @@ -603,6 +618,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => // not match the abstract method in Application and an abstract class error results. def typedArg(arg: tpd.Tree, formal: Type): TypedArg = arg def treeToArg(arg: Tree): Tree = arg + def typeOfArg(arg: Tree) = arg.tpe } /** If `app` is a `this(...)` constructor call, the this-call argument context, @@ -1263,7 +1279,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic => def sizeFits(alt: TermRef, tp: Type): Boolean = tp match { case tp: PolyType => sizeFits(alt, tp.resultType) - case MethodType(_, ptypes) => + case tp: MethodType => + val ptypes = tp.paramTypes val numParams = ptypes.length def isVarArgs = ptypes.nonEmpty && ptypes.last.isRepeatedParam def hasDefault = alt.symbol.hasDefaultParams diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index f822f8893..b43391592 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -441,7 +441,6 @@ object Checking { case List(param) => if (param.is(Mutable)) ctx.error("value class parameter must not be a var", param.pos) - case _ => ctx.error("value class needs to have exactly one val parameter", clazz.pos) } @@ -625,6 +624,24 @@ trait Checking { case _ => } } + + /** Check that method parameter types do not reference their own parameter + * or later parameters in the same parameter section. + */ + def checkNoForwardDependencies(vparams: List[ValDef])(implicit ctx: Context): Unit = vparams match { + case vparam :: vparams1 => + val check = new TreeTraverser { + def traverse(tree: Tree)(implicit ctx: Context) = tree match { + case id: Ident if vparams.exists(_.symbol == id.symbol) => + ctx.error("illegal forward reference to method parameter", id.pos) + case _ => + traverseChildren(tree) + } + } + check.traverse(vparam.tpt) + checkNoForwardDependencies(vparams1) + case Nil => + } } trait NoChecking extends Checking { @@ -642,4 +659,5 @@ trait NoChecking extends Checking { override def checkNotSingleton(tpt: Tree, where: String)(implicit ctx: Context): Tree = tpt override def checkDerivedValueClass(clazz: Symbol, stats: List[Tree])(implicit ctx: Context) = () override def checkTraitInheritance(parentSym: Symbol, cls: ClassSymbol, pos: Position)(implicit ctx: Context) = () + override def checkNoForwardDependencies(vparams: List[ValDef])(implicit ctx: Context): Unit = () } diff --git a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala index e7e7ece78..57c1808c9 100644 --- a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala +++ b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala @@ -59,8 +59,8 @@ object EtaExpansion { */ def liftArgs(defs: mutable.ListBuffer[Tree], methRef: Type, args: List[Tree])(implicit ctx: Context) = methRef.widen match { - case MethodType(paramNames, paramTypes) => - (args, paramNames, paramTypes).zipped map { (arg, name, tp) => + case mt: MethodType => + (args, mt.paramNames, mt.paramTypes).zipped map { (arg, name, tp) => if (tp.isInstanceOf[ExprType]) arg else liftArg(defs, arg, if (name contains '$') "" else name.toString + "$") } diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index b588e3ae5..f7dd725c8 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -237,6 +237,12 @@ object ProtoTypes { typer.adapt(targ, formal, arg) } + /** The type of the argument `arg`. + * @pre `arg` has been typed before + */ + def typeOfArg(arg: untpd.Tree)(implicit ctx: Context): Type = + myTypedArg(arg).tpe + private var myTupled: Type = NoType /** The same proto-type but with all arguments combined in a single tuple */ diff --git a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala index 3252ead47..6080c6644 100644 --- a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala +++ b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala @@ -85,8 +85,8 @@ class ReTyper extends Typer { override def encodeName(tree: untpd.NameTree)(implicit ctx: Context) = tree override def handleUnexpectedFunType(tree: untpd.Apply, fun: Tree)(implicit ctx: Context): Tree = fun.tpe match { - case mt @ MethodType(_, formals) => - val args: List[Tree] = tree.args.zipWithConserve(formals)(typedExpr(_, _)).asInstanceOf[List[Tree]] + case mt: MethodType => + val args: List[Tree] = tree.args.zipWithConserve(mt.paramTypes)(typedExpr(_, _)).asInstanceOf[List[Tree]] assignType(untpd.cpy.Apply(tree)(fun, args), fun, args) case _ => super.handleUnexpectedFunType(tree, fun) diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index e8ff7d572..d61f5fa68 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -739,11 +739,7 @@ import RefChecks._ * * 2. It warns about references to symbols labeled deprecated or migration. - * 3. It performs the following transformations: - * - * - if (true) A else B --> A - * if (false) A else B --> B - * - macro definitions are eliminated. + * 3. It eliminates macro definitions. * * 4. It makes members not private where necessary. The following members * cannot be private in the Java model: @@ -836,12 +832,6 @@ class RefChecks extends MiniPhase { thisTransformer => tree } - override def transformIf(tree: If)(implicit ctx: Context, info: TransformerInfo) = - tree.cond.tpe match { - case ConstantType(value) => if (value.booleanValue) tree.thenp else tree.elsep - case _ => tree - } - override def transformNew(tree: New)(implicit ctx: Context, info: TransformerInfo) = { currentLevel.enterReference(tree.tpe.typeSymbol, tree.pos) tree diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 6bf8dcbbc..6e774e38e 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -315,10 +315,10 @@ trait TypeAssigner { def assignType(tree: untpd.Apply, fn: Tree, args: List[Tree])(implicit ctx: Context) = { val ownType = fn.tpe.widen match { - case fntpe @ MethodType(_, ptypes) => - if (sameLength(ptypes, args) || ctx.phase.prev.relaxedTyping) fntpe.instantiate(args.tpes) + case fntpe: MethodType => + if (sameLength(fntpe.paramTypes, args) || ctx.phase.prev.relaxedTyping) fntpe.instantiate(args.tpes) else - errorType(i"wrong number of arguments for $fntpe: ${fn.tpe}, expected: ${ptypes.length}, found: ${args.length}", tree.pos) + errorType(i"wrong number of arguments for $fntpe: ${fn.tpe}, expected: ${fntpe.paramTypes.length}, found: ${args.length}", tree.pos) case t => errorType(i"${err.exprStr(fn)} does not take parameters", tree.pos) } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index ccfe218b3..d4a9744e4 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -672,8 +672,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit // this can type the greatest set of admissible closures. (pt.dealias.argTypesLo.init, pt.dealias.argTypesHi.last) case SAMType(meth) => - val mt @ MethodType(_, paramTypes) = meth.info - (paramTypes, mt.resultType) + val MethodTpe(_, formals, restpe) = meth.info + (formals, restpe) case _ => (List.range(0, defaultArity) map alwaysWildcardType, WildcardType) } @@ -1080,6 +1080,13 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit (if (isVarPattern(arg)) desugar.patternVar(arg) else arg, tparam.paramBounds) else (arg, WildcardType) + if (tpt1.symbol.isClass) + tparam match { + case tparam: Symbol => + // This is needed to get the test `compileParSetSubset` to work + tparam.ensureCompleted() + case _ => + } typed(desugaredArg, argPt) } args.zipWithConserve(tparams)(typedArg(_, _)).asInstanceOf[List[Tree]] @@ -1222,6 +1229,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit completeAnnotations(ddef, sym) val tparams1 = tparams mapconserve (typed(_).asInstanceOf[TypeDef]) val vparamss1 = vparamss nestedMapconserve (typed(_).asInstanceOf[ValDef]) + vparamss1.foreach(checkNoForwardDependencies) if (sym is Implicit) checkImplicitParamsNotSingletons(vparamss1) var tpt1 = checkSimpleKinded(typedType(tpt)) @@ -1280,10 +1288,10 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def maybeCall(ref: Tree, psym: Symbol, cinfo: Type): Tree = cinfo match { case cinfo: PolyType => maybeCall(ref, psym, cinfo.resultType) - case cinfo @ MethodType(Nil, _) if cinfo.resultType.isInstanceOf[ImplicitMethodType] => + case cinfo @ MethodType(Nil) if cinfo.resultType.isInstanceOf[ImplicitMethodType] => val icall = New(ref).select(nme.CONSTRUCTOR).appliedToNone typedExpr(untpd.TypedSplice(icall))(superCtx) - case cinfo @ MethodType(Nil, _) if !cinfo.resultType.isInstanceOf[MethodType] => + case cinfo @ MethodType(Nil) if !cinfo.resultType.isInstanceOf[MethodType] => ref case cinfo: MethodType => if (!ctx.erasedTypes) { // after constructors arguments are passed in super call. diff --git a/compiler/src/dotty/tools/dotc/typer/Variances.scala b/compiler/src/dotty/tools/dotc/typer/Variances.scala index 92bd9fd74..5a1745930 100644 --- a/compiler/src/dotty/tools/dotc/typer/Variances.scala +++ b/compiler/src/dotty/tools/dotc/typer/Variances.scala @@ -79,8 +79,8 @@ object Variances { varianceInType(parent)(tparam) & varianceInType(rinfo)(tparam) case tp: RecType => varianceInType(tp.parent)(tparam) - case tp @ MethodType(_, paramTypes) => - flip(varianceInTypes(paramTypes)(tparam)) & varianceInType(tp.resultType)(tparam) + case tp: MethodType => + flip(varianceInTypes(tp.paramTypes)(tparam)) & varianceInType(tp.resultType)(tparam) case ExprType(restpe) => varianceInType(restpe)(tparam) case tp @ HKApply(tycon, args) => diff --git a/compiler/src/dotty/tools/io/Jar.scala b/compiler/src/dotty/tools/io/Jar.scala index 42efc7e06..142226ea5 100644 --- a/compiler/src/dotty/tools/io/Jar.scala +++ b/compiler/src/dotty/tools/io/Jar.scala @@ -12,6 +12,7 @@ import java.util.jar._ import scala.collection.JavaConverters._ import Attributes.Name import scala.language.{postfixOps, implicitConversions} +import scala.annotation.tailrec // Attributes.Name instances: // @@ -109,7 +110,7 @@ class JarWriter(val file: File, val manifest: Manifest) { private def transfer(in: InputStream, out: OutputStream) = { val buf = new Array[Byte](10240) - def loop(): Unit = in.read(buf, 0, buf.length) match { + @tailrec def loop(): Unit = in.read(buf, 0, buf.length) match { case -1 => in.close() case n => out.write(buf, 0, n) ; loop } diff --git a/compiler/src/strawman/collections/CollectionStrawMan6.scala b/compiler/src/strawman/collections/CollectionStrawMan6.scala index 50de63488..c2b87cb0b 100644 --- a/compiler/src/strawman/collections/CollectionStrawMan6.scala +++ b/compiler/src/strawman/collections/CollectionStrawMan6.scala @@ -244,7 +244,7 @@ object CollectionStrawMan6 extends LowPriority { * collection type. */ override def drop(n: Int): C[A @uncheckedVariance] = { // sound bcs of VarianceNote - def loop(n: Int, s: Iterable[A]): C[A] = + @tailrec def loop(n: Int, s: Iterable[A]): C[A] = if (n <= 0) s.asInstanceOf[C[A]] // implicit contract to guarantee success of asInstanceOf: // (1) coll is of type C[A] |