From 1a490393d766039332bfccb8b85f264f22c9e9cc Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 1 Mar 2017 09:35:30 +0100 Subject: Make loop in derivesFrom a tailrec loop. --- compiler/src/dotty/tools/dotc/core/Types.scala | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'compiler/src/dotty/tools/dotc/core/Types.scala') diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 200e94a1e..3258a1d57 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -153,16 +153,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 _ => @@ -1011,7 +1011,7 @@ object Types { } else NoType case SkolemType(tp) => - tp.lookupRefined(name) + loop(tp) case pre: WildcardType => WildcardType case pre: TypeRef => -- cgit v1.2.3 From be5720c18ca6768c7e72d4258677952848db2bb4 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 1 Mar 2017 10:11:49 +0100 Subject: Add @tailrec to avoid regressions. --- compiler/src/dotty/tools/dotc/ast/tpd.scala | 2 +- .../src/dotty/tools/dotc/config/Settings.scala | 3 +- compiler/src/dotty/tools/dotc/core/Signature.scala | 4 +- .../src/dotty/tools/dotc/core/SymDenotations.scala | 4 +- .../src/dotty/tools/dotc/core/TypeErasure.scala | 3 +- compiler/src/dotty/tools/dotc/core/Types.scala | 60 +++++++++++----------- .../src/dotty/tools/dotc/rewrite/Rewrites.scala | 3 +- .../dotty/tools/dotc/transform/ExplicitOuter.scala | 4 +- .../src/dotty/tools/dotc/transform/SymUtils.scala | 6 ++- compiler/src/dotty/tools/io/Jar.scala | 3 +- .../strawman/collections/CollectionStrawMan6.scala | 2 +- compiler/test/dotty/tools/dotc/CompilerTest.scala | 4 +- 12 files changed, 54 insertions(+), 44 deletions(-) (limited to 'compiler/src/dotty/tools/dotc/core/Types.scala') diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index e5904156f..458e94b6e 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -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/Settings.scala b/compiler/src/dotty/tools/dotc/config/Settings.scala index 58fa6d366..c2763cdf0 100644 --- a/compiler/src/dotty/tools/dotc/config/Settings.scala +++ b/compiler/src/dotty/tools/dotc/config/Settings.scala @@ -6,6 +6,7 @@ import scala.util.{ Try, Success, Failure } import scala.reflect.internal.util.StringOps 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 @@ -217,7 +218,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/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 a3475e14c..8e3b73fc0 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1040,7 +1040,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 @@ -1056,7 +1056,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/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index ff99008bb..fc18808a3 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)) if (!bc.is(Trait) && bc != defn.AnyClass) bc diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 3258a1d57..6ff896110 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -105,7 +105,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 @@ -188,7 +188,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 } @@ -277,7 +277,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? @@ -292,16 +292,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 @@ -325,9 +325,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) => @@ -337,7 +337,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 @@ -368,11 +368,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 } @@ -394,7 +394,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 => @@ -620,7 +620,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 => @@ -827,7 +827,7 @@ object Types { * def o: Outer * .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 } @@ -835,7 +835,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 } @@ -843,7 +843,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 } @@ -857,7 +857,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 @@ -880,20 +880,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 } @@ -913,7 +913,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 } @@ -996,7 +996,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) => @@ -1004,7 +1004,7 @@ 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 @@ -1051,7 +1051,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 => @@ -1107,14 +1107,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 @@ -2101,7 +2101,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) @@ -3676,7 +3676,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 @@ -3719,7 +3719,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/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/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala index d75c32fcc..44308012e 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 @@ -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") 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/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] diff --git a/compiler/test/dotty/tools/dotc/CompilerTest.scala b/compiler/test/dotty/tools/dotc/CompilerTest.scala index 5d16917cc..db12994f4 100644 --- a/compiler/test/dotty/tools/dotc/CompilerTest.scala +++ b/compiler/test/dotty/tools/dotc/CompilerTest.scala @@ -500,12 +500,12 @@ abstract class CompilerTest { * that aren't in extensionsToCopy. */ private def recCopyFiles(sourceFile: Path, dest: Path): Unit = { - def copyfile(file: SFile, bytewise: Boolean): Unit = { + @tailrec def copyfile(file: SFile, bytewise: Boolean): Unit = { if (bytewise) { val in = file.inputStream() val out = SFile(dest).outputStream() val buffer = new Array[Byte](1024) - def loop(available: Int):Unit = { + @tailrec def loop(available: Int):Unit = { if (available < 0) {()} else { out.write(buffer, 0, available) -- cgit v1.2.3