From 1258a12712ca48907e70c4e870571eff30f4bfbb Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 2 Apr 2008 16:42:48 +0000 Subject: removed contractiveness requirement for implici... removed contractiveness requirement for implicit methods --- src/compiler/scala/tools/nsc/symtab/Names.scala | 4 +- .../scala/tools/nsc/typechecker/Namers.scala | 6 +-- .../scala/tools/nsc/typechecker/Typers.scala | 44 +++++++++++++++++++++- src/library/scala/Predef.scala | 16 ++++---- test/files/neg/bug696.check | 7 +--- 5 files changed, 56 insertions(+), 21 deletions(-) diff --git a/src/compiler/scala/tools/nsc/symtab/Names.scala b/src/compiler/scala/tools/nsc/symtab/Names.scala index 70da3a3cb5..83ba15d128 100644 --- a/src/compiler/scala/tools/nsc/symtab/Names.scala +++ b/src/compiler/scala/tools/nsc/symtab/Names.scala @@ -22,8 +22,8 @@ class Names { private final val HASH_SIZE = 0x8000 private final val HASH_MASK = 0x7FFF private final val NAME_SIZE = 0x20000 - private final val MAX_LEN = 255 // for longer names use a partial MD5 hash - private final val PREFIX_LEN = 128 // the length of the prefix to keep unhashed + private final val MAX_LEN = 240 // for longer names use a partial MD5 hash + private final val PREFIX_LEN = 100 // the length of the prefix to keep unhashed private final val SUFFIX_LEN = 64 // the length of the suffix to keep unhashed final val nameDebug = false diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index b3538763d7..5ed868d779 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -810,9 +810,9 @@ trait Namers { self: Analyzer => clazz.tpe case DefDef(_, _, tparams, vparamss, tpt, rhs) => - val result = - newNamer(context.makeNewScope(tree, sym)).methodSig(tparams, vparamss, tpt, rhs); - checkContractive(sym, result) + //val result = + newNamer(context.makeNewScope(tree, sym)).methodSig(tparams, vparamss, tpt, rhs) + //checkContractive(sym, result) case vdef @ ValDef(mods, _, tpt, rhs) => val typer1 = typer.constrTyperIf(sym.hasFlag(PARAM | PRESUPER) && sym.owner.isConstructor) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index a43418f6bd..c34212cd8d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -134,6 +134,8 @@ trait Typers { self: Analyzer => private def argMode(fun: Tree, mode: Int) = if (treeInfo.isSelfOrSuperConstrCall(fun)) mode | SCCmode else mode + private var pendingImplicits: List[Type] = List() + abstract class Typer(context0: Context) { import context0.unit @@ -3294,18 +3296,56 @@ trait Typers { self: Analyzer => case _ => tp.isError } + private def dominates(dtor: Type, dted: Type): Boolean = { + def simplify(tp: Type): Type = tp match { + case RefinedType(parents, defs) => intersectionType(parents, tp.typeSymbol.owner) + case AnnotatedType(attribs, tp, selfsym) => tp + case _ => tp + } + def sum(xs: List[Int]) = (0 /: xs)(_ + _) + def complexity(tp: Type): Int = tp match { + case SingleType(pre, sym) => complexity(pre) + 1 + case TypeRef(pre, sym, args) => complexity(pre) + sum(args map complexity) + 1 + case TypeBounds(lo, hi) => complexity(lo) + complexity(hi) + case ClassInfoType(parents, defs, clazz) => sum(parents map complexity) + 1 + case MethodType(paramtypes, result) => sum(paramtypes map complexity) + complexity(result) + 1 + case PolyType(tparams, result) => sum(tparams map (_.info) map complexity) + complexity(result) + 1 + case ExistentialType(tparams, result) => sum(tparams map (_.info) map complexity) + complexity(result) + 1 + case _ => 1 + } + val dtor1 = simplify(dtor) + val dted1 = simplify(dted) + (dtor1.typeSymbol == dted1.typeSymbol) && + (dtor1 =:= dted1 || complexity(dtor1) > complexity(dted1)) + } + /** Try to construct a typed tree from given implicit info with given * expected type. * * @param pos Position for error reporting * @param info The given implicit info describing the implicit definition - * @param pt The expected type + * @param pt0 The unnormalized expected type + * @param pt The normalized expected type * @param isLocal Is implicit definition visible without prefix? * @return A typed tree if the implicit info can be made to conform * to pt, EmptyTree otherwise. * @pre info.tpe does not contain an error */ - private def typedImplicit(pos: Position, info: ImplicitInfo, pt0: Type, pt: Type, isLocal: Boolean): Tree = { + private def typedImplicit(pos: Position, info: ImplicitInfo, pt0: Type, pt: Type, isLocal: Boolean): Tree = + pendingImplicits find (dominates(pt, _)) match { + case Some(pending) => + context.error(pos, "diverging implicit expansion for type "+pending) + EmptyTree + case None => + try { + pendingImplicits = pt :: pendingImplicits + typedImplicit0(pos, info, pt0, pt, isLocal) + } finally { + pendingImplicits = pendingImplicits.tail + } + } + + private def typedImplicit0(pos: Position, info: ImplicitInfo, pt0: Type, pt: Type, isLocal: Boolean): Tree = { def isStable(tp: Type): Boolean = tp match { case TypeRef(pre, sym, _) => sym.isPackageClass || sym.isModuleClass && isStable(pre) case _ => tp.isStable diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala index 6db07a6bd6..74409b1e4b 100644 --- a/src/library/scala/Predef.scala +++ b/src/library/scala/Predef.scala @@ -126,6 +126,14 @@ object Predef { def unapply[A, B, C](x: Tuple3[A, B, C]): Option[Tuple3[A, B, C]] = Some(x) } + class Ensuring[A](x: A) { + def ensuring(cond: Boolean): A = { assert(cond); x } + def ensuring(cond: Boolean, msg: Any): A = { assert(cond, msg); x } + def ensuring(cond: A => Boolean): A = { assert(cond(x)); x } + def ensuring(cond: A => Boolean, msg: Any): A = { assert(cond(x), msg); x } + } + implicit def any2Ensuring[A](x: A): Ensuring[A] = new Ensuring(x) + class ArrowAssoc[A](x: A) { def -> [B](y: B): Tuple2[A, B] = Tuple2(x, y) } @@ -183,14 +191,6 @@ object Predef { implicit def any2stringadd(x: Any) = new runtime.StringAdd(x) - class Ensuring[A](x: A) { - def ensuring(cond: Boolean): A = { assert(cond); x } - def ensuring(cond: Boolean, msg: Any): A = { assert(cond, msg); x } - def ensuring(cond: A => Boolean): A = { assert(cond(x)); x } - def ensuring(cond: A => Boolean, msg: Any): A = { assert(cond(x), msg); x } - } - implicit def any2Ensuring[A](x: A): Ensuring[A] = new Ensuring(x) - implicit def exceptionWrapper(exc: Throwable) = new runtime.RichException(exc) implicit def unit2ordered(x: Unit): Ordered[Unit] = new Ordered[Unit] with Proxy { diff --git a/test/files/neg/bug696.check b/test/files/neg/bug696.check index 2bc09820ed..7d9d2687b0 100644 --- a/test/files/neg/bug696.check +++ b/test/files/neg/bug696.check @@ -1,9 +1,4 @@ -bug696.scala:3: error: implicit method WithType is not contractive, - because the implicit parameter type TypeUtil0.Type[S] - is not strictly contained in the signature TypeUtil0.Type[S with T] - implicit def WithType[S,T](implicit tpeS : Type[S], tpeT : Type[T]) : Type[S with T] = null - ^ bug696.scala:4: error: no implicit argument matching parameter type TypeUtil0.Type[Any] was found. as[Any](null); ^ -two errors found +one error found -- cgit v1.2.3