diff options
-rw-r--r-- | sabbus.xml | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/Parsers.scala | 68 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Contexts.scala | 28 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 47 | ||||
-rw-r--r-- | src/library/jvm/scala/Predef.scala | 2 | ||||
-rw-r--r-- | test/files/neg/bug696.check | 3 | ||||
-rw-r--r-- | test/files/neg/divergent-implicit.check | 17 | ||||
-rw-r--r-- | test/files/neg/divergent-implicit.scala | 16 | ||||
-rwxr-xr-x | test/files/run/existentials.scala | 2 |
10 files changed, 122 insertions, 65 deletions
diff --git a/sabbus.xml b/sabbus.xml index ae4a142189..b2d7ec2b2a 100644 --- a/sabbus.xml +++ b/sabbus.xml @@ -92,7 +92,7 @@ PROPERTIES <property name="copyright.string" value="Copyright 2002-2008, LAMP/EPFL"/> - <property name="java.flags" value="-Xmx256M -Xms16M"/> + <property name="java.flags" value="-Xmx256M -Xms32M"/> <!-- =========================================================================== INITIALISATION diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 04334951ec..fd1db30e74 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -191,8 +191,11 @@ trait Parsers extends NewScanners with MarkupParsers { val savedPlaceholderTypes = placeholderTypes placeholderTypes = List() var t = op - if (!placeholderTypes.isEmpty) t = ExistentialTypeTree(t, placeholderTypes.reverse) - placeholderTypes = savedPlaceholderTypes + if (!placeholderTypes.isEmpty && t.isInstanceOf[AppliedTypeTree]) { + t = ExistentialTypeTree(t, placeholderTypes.reverse) + placeholderTypes = List() + } + placeholderTypes = placeholderTypes ::: savedPlaceholderTypes t } @@ -646,7 +649,7 @@ trait Parsers extends NewScanners with MarkupParsers { /** TypedOpt ::= [`:' Type] */ def typedOpt(): Tree = - if (inToken == COLON) { inNextToken; placeholderTypeBoundary(typ()) } + if (inToken == COLON) { inNextToken; typ() } else TypeTree() /** RequiresTypedOpt ::= [requires AnnotType] @@ -654,7 +657,7 @@ trait Parsers extends NewScanners with MarkupParsers { def requiresTypeOpt(): Tree = if (inToken == REQUIRES) { deprecationWarning(in.currentPos, "`requires T' has been deprecated; use `{ self: T => ...' instead") - inNextToken; placeholderTypeBoundary(annotType(false)) + inNextToken; annotType(false) } else TypeTree() /** Types ::= Type {`,' Type} @@ -686,24 +689,26 @@ trait Parsers extends NewScanners with MarkupParsers { * ExistentialClause ::= forSome `{' ExistentialDcl {semi ExistentialDcl}} `}' * ExistentialDcl ::= type TypeDcl | val ValDcl */ - def typ(): Tree = { + def typ(): Tree = typ(false) + + def typ(isPattern: Boolean): Tree = placeholderTypeBoundary { val t = if (inToken == LPAREN) { val pos = inSkipToken if (inToken == RPAREN) { inNextToken - atPos(accept(ARROW)) { makeFunctionTypeTree(List(), typ()) } + atPos(accept(ARROW)) { makeFunctionTypeTree(List(), typ(isPattern)) } /* Not more used } else if (inToken == ARROW) { inNextToken - val t0 = typ() + val t0 = typ(isPattern) accept(RPAREN) - atPos(accept(ARROW)) { makeByNameFunctionTypeTree(t0, typ()) } + atPos(accept(ARROW)) { makeByNameFunctionTypeTree(t0, typ(isPattern)) } */ } else { - val ts = types(false, false, true) + val ts = types(isPattern, false, true) accept(RPAREN) - if (inToken == ARROW) atPos(inSkipToken) { makeFunctionTypeTree(ts, typ()) } + if (inToken == ARROW) atPos(inSkipToken) { makeFunctionTypeTree(ts, typ(isPattern)) } else { for (t <- ts) t match { case AppliedTypeTree(Select(_, n), _) @@ -711,15 +716,15 @@ trait Parsers extends NewScanners with MarkupParsers { syntaxError(t.pos, "no by-name parameter type allowed here", false) case _ => } - infixTypeRest(pos, annotTypeRest(pos, false, makeTupleType(ts, true)), false, InfixMode.FirstOp) + infixTypeRest(pos, annotTypeRest(pos, isPattern, makeTupleType(ts, true)), false, InfixMode.FirstOp) } } } else { - infixType(false, InfixMode.FirstOp) + infixType(isPattern, InfixMode.FirstOp) } if (inToken == ARROW) atPos(inSkipToken) { - makeFunctionTypeTree(List(t), typ()) + makeFunctionTypeTree(List(t), typ(isPattern)) } else if (inToken == FORSOME) atPos(inSkipToken) { @@ -739,8 +744,9 @@ trait Parsers extends NewScanners with MarkupParsers { /** InfixType ::= CompoundType {id [nl] CompoundType} */ - def infixType(isPattern: Boolean, mode: InfixMode.Value): Tree = + def infixType(isPattern: Boolean, mode: InfixMode.Value): Tree = placeholderTypeBoundary { infixTypeRest(inCurrentPos, infixTypeFirst(isPattern), isPattern, mode) + } def infixTypeFirst(isPattern: Boolean) = if (inToken == LBRACE) scalaAnyRefConstr else annotType(isPattern) @@ -790,7 +796,7 @@ trait Parsers extends NewScanners with MarkupParsers { * | `(' Types [`,'] `)' * | WildcardType */ - def annotType(isPattern: Boolean): Tree = { + def annotType(isPattern: Boolean): Tree = placeholderTypeBoundary { val annots1 = annotations() if (!annots1.isEmpty) deprecationWarning( @@ -864,7 +870,7 @@ trait Parsers extends NewScanners with MarkupParsers { Bind(ident().toTypeName, EmptyTree) } else { - typ() + typ(true) } } else if (isFuncArg) { // copy-paste (with change) from def paramType @@ -884,7 +890,7 @@ trait Parsers extends NewScanners with MarkupParsers { } else t } } else if (isTypeApply) { - placeholderTypeBoundary(typ()) + typ() } else { typ() } @@ -1045,8 +1051,7 @@ trait Parsers extends NewScanners with MarkupParsers { } } else if (annots.isEmpty || isTypeIntro) { t = atPos(pos) { - val tpt = placeholderTypeBoundary( - if (location != Local) compoundType(false) else typ()) + val tpt = if (location != Local) compoundType(false) else typ() if (isWildcard(t)) (placeholderParams: @unchecked) match { case (vd @ ValDef(mods, name, _, _)) :: rest => @@ -1072,10 +1077,11 @@ trait Parsers extends NewScanners with MarkupParsers { } stripParens(t) } - if (!placeholderParams.isEmpty) - if (isWildcard(res)) savedPlaceholderParams = placeholderParams ::: savedPlaceholderParams - else res = atPos(res.pos){Function(placeholderParams.reverse, res)} - placeholderParams = savedPlaceholderParams + if (!placeholderParams.isEmpty && !isWildcard(res)) { + res = atPos(res.pos){ Function(placeholderParams.reverse, res) } + placeholderParams = List() + } + placeholderParams = placeholderParams ::: savedPlaceholderParams res } @@ -1356,7 +1362,7 @@ trait Parsers extends NewScanners with MarkupParsers { val p = pattern2(seqOK) p match { case Ident(name) if (treeInfo.isVarPattern(p) && inToken == COLON) => - atPos(inSkipToken) { Typed(p, placeholderTypeBoundary(compoundType(true))) } + atPos(inSkipToken) { Typed(p, compoundType(true)) } case _ => p } @@ -1746,10 +1752,10 @@ trait Parsers extends NewScanners with MarkupParsers { if (inToken == ARROW) atPos(inSkipToken) { AppliedTypeTree( - scalaDot(nme.BYNAME_PARAM_CLASS_NAME.toTypeName), List(placeholderTypeBoundary(typ()))) + scalaDot(nme.BYNAME_PARAM_CLASS_NAME.toTypeName), List(typ())) } else { - val t = placeholderTypeBoundary(typ()) + val t = typ() if (isIdent && inName == STAR) { inNextToken atPos(t.pos) { @@ -1789,7 +1795,7 @@ trait Parsers extends NewScanners with MarkupParsers { val param = atPos(pos) { TypeDef(mods, pname, tparams, typeBounds()) } if (inToken == VIEWBOUND && (implicitViewBuf ne null)) implicitViewBuf += atPos(inSkipToken) { - makeFunctionTypeTree(List(Ident(pname)), placeholderTypeBoundary(typ())) + makeFunctionTypeTree(List(Ident(pname)), typ()) } param } @@ -1815,7 +1821,7 @@ trait Parsers extends NewScanners with MarkupParsers { bound(SUBTYPE, nme.Any)) def bound(tok: Int, default: Name): Tree = - if (inToken == tok) { inNextToken; placeholderTypeBoundary(typ()) } + if (inToken == tok) { inNextToken; typ() } else scalaDot(default.toTypeName) //////// DEFS //////////////////////////////////////////////////////////////// @@ -2125,7 +2131,7 @@ trait Parsers extends NewScanners with MarkupParsers { inToken match { case EQUALS => inNextToken - TypeDef(mods, name, tparams, placeholderTypeBoundary(typ())) + TypeDef(mods, name, tparams, typ()) case SUPERTYPE | SUBTYPE | SEMI | NEWLINE | NEWLINES | COMMA | RBRACE => TypeDef(mods | Flags.DEFERRED, name, tparams, typeBounds()) case _ => @@ -2222,14 +2228,14 @@ trait Parsers extends NewScanners with MarkupParsers { * TraitParents ::= AnnotType {with AnnotType} */ def templateParents(isTrait: Boolean): (List[Tree], List[List[Tree]]) = { - val parents = new ListBuffer[Tree] + placeholderTypeBoundary(annotType(false)) + val parents = new ListBuffer[Tree] + annotType(false) val argss = new ListBuffer[List[Tree]] if (inToken == LPAREN && !isTrait) do { argss += argumentExprs() } while (inToken == LPAREN) else argss += List() while (inToken == WITH) { inNextToken - parents += placeholderTypeBoundary(annotType(false)) + parents += annotType(false) } (parents.toList, argss.toList) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 1f0750d580..758a006e0e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -97,8 +97,9 @@ trait Contexts { self: Analyzer => private var _undetparams: List[Symbol] = List() // Undetermined type parameters, // not inherited to child contexts var depth: Int = 0 - var imports: List[ImportInfo] = List() - + var imports: List[ImportInfo] = List() // currently visible imports + var openImplicits: List[Type] = List() // types for which implicit arguments + // are currently searched var prefix: Type = NoPrefix var inConstructorSuffix = false // are we in a secondary constructor // after the this constructor call? @@ -130,6 +131,7 @@ trait Contexts { self: Analyzer => txt._undetparams = _undetparams txt.depth = depth txt.imports = imports + txt.openImplicits = openImplicits txt.prefix = prefix txt.inConstructorSuffix = inConstructorSuffix txt.returnsSeen = returnsSeen @@ -169,15 +171,16 @@ trait Contexts { self: Analyzer => val a8 = eq(depth, that.depth) val a9 = eq(imports, that.imports) - val a10 = eq(prefix, that.prefix) - val a11 = eq(inConstructorSuffix, that.inConstructorSuffix) - val a12 = eq(implicitsEnabled, that.implicitsEnabled) - val a13 = eq(checking, that.checking) - val a14 = eq(retyping, that.retyping) - val a15 = eq(savedTypeBounds, that.savedTypeBounds) - val a16 = eq(unit, that.unit) - val ret = a0 && a1 && a2 && a3 && a4 && a5 && a6 && a7 && a8 && a9 && a10 && a11 && a12 && a13 && a14 && a15 && a16 - val a17 = { + val a10 = eq(openImplicits, that.openImplicits) + val a11 = eq(prefix, that.prefix) + val a12 = eq(inConstructorSuffix, that.inConstructorSuffix) + val a13 = eq(implicitsEnabled, that.implicitsEnabled) + val a14 = eq(checking, that.checking) + val a15 = eq(retyping, that.retyping) + val a16 = eq(savedTypeBounds, that.savedTypeBounds) + val a17 = eq(unit, that.unit) + val ret = a0 && a1 && a2 && a3 && a4 && a5 && a6 && a7 && a8 && a9 && a10 && a11 && a12 && a13 && a14 && a15 && a16 && a17 + val a18 = { if (implicitsRunId > that.implicitsRunId) { that.implicitsRunId = NoRunId that.implicitsCache = null @@ -189,7 +192,7 @@ trait Contexts { self: Analyzer => implicitsCache == that.implicitsCache } if (ret) { - if (!a17) { + if (!a18) { //assert(this.implicitsCache == null || that.implicitsCache == null) } } @@ -252,6 +255,7 @@ trait Contexts { self: Analyzer => c.implicitsEnabled = this.implicitsEnabled c.checking = this.checking c.retyping = this.retyping + c.openImplicits = this.openImplicits c } diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index e3a4ae897d..89b4b85cb0 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -265,7 +265,7 @@ trait SyntheticMethods { self: Analyzer => stat.symbol.resetFlag(CASEACCESSOR) } } - if (!inIDE && clazz.info.nonPrivateDecl(nme.tag) == NoSymbol) ts += tagMethod + if (!inIDE && !clazz.hasFlag(INTERFACE) && clazz.info.nonPrivateDecl(nme.tag) == NoSymbol) ts += tagMethod } if (clazz.isModuleClass) { if (!hasOverridingImplementation(Object_toString)) ts += moduleToStringMethod diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index c34212cd8d..12e0e63960 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -134,7 +134,7 @@ 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() + private val DivergentImplicit = new Exception() abstract class Typer(context0: Context) { import context0.unit @@ -3297,26 +3297,28 @@ trait Typers { self: Analyzer => } 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 + def core(tp: Type): Type = tp.normalize match { + case RefinedType(parents, defs) => intersectionType(parents map core, tp.typeSymbol.owner) + case AnnotatedType(attribs, tp, selfsym) => core(tp) + case ExistentialType(tparams, result) => core(result).subst(tparams, tparams map (t => core(t.info.bounds.hi))) + case PolyType(tparams, result) => core(result).subst(tparams, tparams map (t => core(t.info.bounds.hi))) 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 RefinedType(parents, _) => sum(parents map complexity) + 1 case _ => 1 } - val dtor1 = simplify(dtor) - val dted1 = simplify(dted) - (dtor1.typeSymbol == dted1.typeSymbol) && - (dtor1 =:= dted1 || complexity(dtor1) > complexity(dted1)) + def overlaps(tp1: Type, tp2: Type): Boolean = (tp1, tp2) match { + case (RefinedType(parents, _), _) => parents exists (overlaps(_, tp2)) + case (_, RefinedType(parents, _)) => parents exists (overlaps(tp1, _)) + case _ => tp1.typeSymbol == tp2.typeSymbol + } + val dtor1 = core(dtor) + val dted1 = core(dted) + overlaps(dtor1, dted1) && (dtor1 =:= dted1 || complexity(dtor1) > complexity(dted1)) } /** Try to construct a typed tree from given implicit info with given @@ -3332,16 +3334,27 @@ trait Typers { self: Analyzer => * @pre <code>info.tpe</code> does not contain an error */ private def typedImplicit(pos: Position, info: ImplicitInfo, pt0: Type, pt: Type, isLocal: Boolean): Tree = - pendingImplicits find (dominates(pt, _)) match { + context.openImplicits find (dominates(pt, _)) match { case Some(pending) => - context.error(pos, "diverging implicit expansion for type "+pending) + throw DivergentImplicit EmptyTree case None => try { - pendingImplicits = pt :: pendingImplicits + context.openImplicits = pt :: context.openImplicits typedImplicit0(pos, info, pt0, pt, isLocal) + } catch { + case DivergentImplicit => + if (context.openImplicits.tail.isEmpty) { + if (!(pt.isErroneous)) + context.unit.error( + pos, "diverging implicit expansion for type "+pt+"\nstarting with "+ + info.sym+info.sym.locationString) + EmptyTree + } else { + throw DivergentImplicit + } } finally { - pendingImplicits = pendingImplicits.tail + context.openImplicits = context.openImplicits.tail } } diff --git a/src/library/jvm/scala/Predef.scala b/src/library/jvm/scala/Predef.scala index 74409b1e4b..c7a01d6642 100644 --- a/src/library/jvm/scala/Predef.scala +++ b/src/library/jvm/scala/Predef.scala @@ -187,7 +187,7 @@ object Predef { implicit def booleanWrapper(x: Boolean) = new runtime.RichBoolean(x) implicit def stringWrapper(x: String) = new runtime.RichString(x) - implicit def stringBuilderWrapper(x : StringBuilder) = new runtime.RichStringBuilder(x) + implicit def stringBuilderWrapper(x : StringBuilder): runtime.RichStringBuilder = new runtime.RichStringBuilder(x) implicit def any2stringadd(x: Any) = new runtime.StringAdd(x) diff --git a/test/files/neg/bug696.check b/test/files/neg/bug696.check index 7d9d2687b0..623c95f62c 100644 --- a/test/files/neg/bug696.check +++ b/test/files/neg/bug696.check @@ -1,4 +1,5 @@ -bug696.scala:4: error: no implicit argument matching parameter type TypeUtil0.Type[Any] was found. +bug696.scala:4: error: diverging implicit expansion for type TypeUtil0.Type[Any] +starting with method WithType in object TypeUtil0 as[Any](null); ^ one error found diff --git a/test/files/neg/divergent-implicit.check b/test/files/neg/divergent-implicit.check new file mode 100644 index 0000000000..8d57f92716 --- /dev/null +++ b/test/files/neg/divergent-implicit.check @@ -0,0 +1,17 @@ +divergent-implicit.scala:4: error: diverging implicit expansion for type (Int) => B +starting with method cast in object Test1 + val x1: String = 1 + ^ +divergent-implicit.scala:5: error: diverging implicit expansion for type (Int) => String +starting with method cast in object Test1 + val x2: String = cast[Int, String](1) + ^ +divergent-implicit.scala:14: error: diverging implicit expansion for type (Test2.Baz) => Test2.Bar +starting with method baz2bar in object Test2 + val x: Bar = new Foo + ^ +divergent-implicit.scala:15: error: diverging implicit expansion for type (Test2.Foo) => Test2.Bar +starting with method foo2bar in object Test2 + val y: Bar = new Baz + ^ +four errors found diff --git a/test/files/neg/divergent-implicit.scala b/test/files/neg/divergent-implicit.scala new file mode 100644 index 0000000000..4a356d54f7 --- /dev/null +++ b/test/files/neg/divergent-implicit.scala @@ -0,0 +1,16 @@ +object Test1 { + implicit def cast[A, B](x: A)(implicit c: A => B): B = c(x) + + val x1: String = 1 + val x2: String = cast[Int, String](1) +} +object Test2 { + class Foo + class Bar + class Baz + implicit def foo2bar(x: Foo)(implicit baz2bar: Baz => Bar): Bar = baz2bar(new Baz) + implicit def baz2bar(x: Baz)(implicit foo2bar: Foo => Bar): Bar = foo2bar(new Foo) + + val x: Bar = new Foo + val y: Bar = new Baz +} diff --git a/test/files/run/existentials.scala b/test/files/run/existentials.scala index 9dc9855a75..42711df5f2 100755 --- a/test/files/run/existentials.scala +++ b/test/files/run/existentials.scala @@ -62,7 +62,7 @@ object Test extends Application { case _ => } - def fooW(x : Counter[_] { def name : String }) = x match { + def fooW(x : Counter[T] { def name : String } forSome { type T }) = x match { case ctr: Counter[t] => val c = ctr.newCounter println(ctr.name+" "+ctr.get(ctr.inc(ctr.inc(c)))) |