aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Stucki <nicolas.stucki@gmail.com>2017-03-01 10:11:49 +0100
committerNicolas Stucki <nicolas.stucki@gmail.com>2017-03-01 13:03:44 +0100
commitbe5720c18ca6768c7e72d4258677952848db2bb4 (patch)
treea781b4f8b2772de09db54352d2d50602a1a0a4a6
parent1a490393d766039332bfccb8b85f264f22c9e9cc (diff)
downloaddotty-be5720c18ca6768c7e72d4258677952848db2bb4.tar.gz
dotty-be5720c18ca6768c7e72d4258677952848db2bb4.tar.bz2
dotty-be5720c18ca6768c7e72d4258677952848db2bb4.zip
Add @tailrec to avoid regressions.
-rw-r--r--compiler/src/dotty/tools/dotc/ast/tpd.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/config/Settings.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/core/Signature.scala4
-rw-r--r--compiler/src/dotty/tools/dotc/core/SymDenotations.scala4
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeErasure.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/core/Types.scala60
-rw-r--r--compiler/src/dotty/tools/dotc/rewrite/Rewrites.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala4
-rw-r--r--compiler/src/dotty/tools/dotc/transform/SymUtils.scala6
-rw-r--r--compiler/src/dotty/tools/io/Jar.scala3
-rw-r--r--compiler/src/strawman/collections/CollectionStrawMan6.scala2
-rw-r--r--compiler/test/dotty/tools/dotc/CompilerTest.scala4
12 files changed, 54 insertions, 44 deletions
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
* <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
}
@@ -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)