From 20f986ecf42cf3018bf3a90b84b2f84669838b10 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 30 Mar 2009 16:21:49 +0000 Subject: changed overloaing resolution to make Builders ... changed overloaing resolution to make Builders work. generalized companion object generation in Namers. Fixed a problem in Types that made the collection build crash. --- src/compiler/scala/tools/nsc/symtab/Types.scala | 2 +- .../scala/tools/nsc/typechecker/Implicits.scala | 12 ++-- .../scala/tools/nsc/typechecker/Infer.scala | 76 +++++++++++++++------- .../scala/tools/nsc/typechecker/Namers.scala | 15 +++-- .../scala/tools/nsc/typechecker/Unapplies.scala | 15 +++-- src/library/scala/runtime/BoxesRunTime.java | 2 + test/files/neg/implicits.check | 7 +- test/files/neg/overload.check | 8 +-- 8 files changed, 89 insertions(+), 48 deletions(-) diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index 828a59f35a..599196ee01 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -1437,7 +1437,7 @@ A type's typeSymbol should never be inspected directly. */ override def bounds: TypeBounds = - if (sym.isAbstractType) transform(thisInfo.bounds).asInstanceOf[TypeBounds] // ??? seems to be doing asSeenFrom twice + if (sym.isAbstractType) thisInfo.bounds // transform(thisInfo.bounds).asInstanceOf[TypeBounds] // ??? seems to be doing asSeenFrom twice else super.bounds override def parents: List[Type] = { diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 0efdc6fbe2..6c7a126ccc 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -105,7 +105,7 @@ self: Analyzer => } /** A sentinel indicating no implicit was found */ - val NoImplicitInfo = new ImplicitInfo(null, null, null) + val NoImplicitInfo = new ImplicitInfo(null, NoType, NoSymbol) /** A class that sets up an implicit search. For more info, see comments for `inferImplicit`. * @param tree The tree for which the implicit needs to be inserted. @@ -463,20 +463,16 @@ self: Analyzer => // Also check that applicable infos that did not get selected are not // in (a companion object of) a subclass of (a companion object of) the class // containing the winning info. + /* for (alt <- applicable.keySet) { - /** Is (the companion class of) `sym1` a subclass of (the compansion class of) `sym2`? */ - def isSubClassOrObject(sym1: Symbol, sym2: Symbol): Boolean = - sym1 != NoSymbol && (sym1 isSubClass sym2) || - sym1.isModuleClass && isSubClassOrObject(sym1.linkedClassOfClass, sym2) || - sym2.isModuleClass && isSubClassOrObject(sym1, sym2.linkedClassOfClass) - - if (alt.sym.owner != best.sym.owner && isSubClassOrObject(alt.sym.owner, best.sym.owner)) { + if (isProperSubClassOrObject(alt.sym.owner, best.sym.owner)) { ambiguousImplicitError(best, alt, "most specific definition is:", "yet alternative definition ", "is defined in a subclass.\n Both definitions ") } } + */ applicable(best) } } // end searchImplicit diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 1a07103e24..55140899ac 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -675,11 +675,11 @@ trait Infer { * @param ftpe2 ... * @return ... */ - def isMoreSpecific(ftpe1: Type, ftpe2: Type): Boolean = ftpe1 match { + def isAsSpecific(ftpe1: Type, ftpe2: Type): Boolean = ftpe1 match { case OverloadedType(pre, alts) => - alts exists (alt => isMoreSpecific(pre.memberType(alt), ftpe2)) + alts exists (alt => isAsSpecific(pre.memberType(alt), ftpe2)) case et: ExistentialType => - et.withTypeVars(isMoreSpecific(_, ftpe2)) // !!! why isStrictly? + et.withTypeVars(isAsSpecific(_, ftpe2)) // !!! why isStrictly? case MethodType(formals @ (x :: xs), _) => isApplicable(List(), ftpe2, formals, WildcardType) case PolyType(_, MethodType(formals @ (x :: xs), _)) => @@ -689,29 +689,58 @@ trait Infer { case _ => ftpe2 match { case OverloadedType(pre, alts) => - alts forall (alt => isMoreSpecific(ftpe1, pre.memberType(alt))) + alts forall (alt => isAsSpecific(ftpe1, pre.memberType(alt))) case et: ExistentialType => - et.withTypeVars(isMoreSpecific(ftpe1, _)) + et.withTypeVars(isAsSpecific(ftpe1, _)) case MethodType(_, _) | PolyType(_, MethodType(_, _)) => true case _ => - isMoreSpecificValueType(ftpe1, ftpe2, List(), List()) + isAsSpecificValueType(ftpe1, ftpe2, List(), List()) } } /* def isStrictlyMoreSpecific(ftpe1: Type, ftpe2: Type): Boolean = - ftpe1.isError || isMoreSpecific(ftpe1, ftpe2) && - (!isMoreSpecific(ftpe2, ftpe1) || + ftpe1.isError || isAsSpecific(ftpe1, ftpe2) && + (!isAsSpecific(ftpe2, ftpe1) || !ftpe1.isInstanceOf[OverloadedType] && ftpe2.isInstanceOf[OverloadedType] || phase.erasedTypes && covariantReturnOverride(ftpe1, ftpe2)) */ - def isStrictlyMoreSpecific(ftpe1: Type, ftpe2: Type, sym1: Symbol, sym2: Symbol): Boolean = - ftpe1.isError || isMoreSpecific(ftpe1, ftpe2) && - (!isMoreSpecific(ftpe2, ftpe1) || - (sym1.owner isSubClass sym2.owner) && (sym1.owner != sym2.owner) || - !ftpe1.isInstanceOf[OverloadedType] && ftpe2.isInstanceOf[OverloadedType] || - phase.erasedTypes && covariantReturnOverride(ftpe1, ftpe2)) + /** Is sym1 (or its companion class in case it is a module) a subclass of + * sym2 (or its companion class in case it is a module)? + */ + def isProperSubClassOrObject(sym1: Symbol, sym2: Symbol): Boolean = + sym1 != sym2 && sym1 != NoSymbol && (sym1 isSubClass sym2) || + sym1.isModuleClass && isProperSubClassOrObject(sym1.linkedClassOfClass, sym2) || + sym2.isModuleClass && isProperSubClassOrObject(sym1, sym2.linkedClassOfClass) + /** is symbol `sym1` defined in a proper subclass of symbol `sym2`? + */ + def isInProperSubClassOrObject(sym1: Symbol, sym2: Symbol) = + sym2 == NoSymbol || isProperSubClassOrObject(sym1.owner, sym2.owner) + + def isStrictlyMoreSpecific(ftpe1: Type, ftpe2: Type, sym1: Symbol, sym2: Symbol): Boolean = + ftpe1.isError || { + val specificCount = (if (isAsSpecific(ftpe1, ftpe2)) 1 else 0) - + (if (isAsSpecific(ftpe2, ftpe1) && + // todo: move to isAsSepecific test + (!ftpe2.isInstanceOf[OverloadedType] || ftpe1.isInstanceOf[OverloadedType]) && + (!phase.erasedTypes || covariantReturnOverride(ftpe1, ftpe2))) 1 else 0) + val subClassCount = (if (isInProperSubClassOrObject(sym1, sym2)) 1 else 0) - + (if (isInProperSubClassOrObject(sym2, sym1)) 1 else 0) + specificCount + subClassCount > 0 + } +/* + ftpe1.isError || { + if (isAsSpecific(ftpe1, ftpe2)) + (!isAsSpecific(ftpe2, ftpe1) || + isProperSubClassOrObject(sym1.owner, sym2.owner) || + !ftpe1.isInstanceOf[OverloadedType] && ftpe2.isInstanceOf[OverloadedType] || + phase.erasedTypes && covariantReturnOverride(ftpe1, ftpe2)) + else + !isAsSpecific(ftpe2, ftpe1) && + isProperSubClassOrObject(sym1.owner, sym2.owner) + } +*/ private def covariantReturnOverride(ftpe1: Type, ftpe2: Type): Boolean = (ftpe1, ftpe2) match { case (MethodType(_, rtpe1), MethodType(_, rtpe2)) => rtpe1 <:< rtpe2 || rtpe2.typeSymbol == ObjectClass @@ -719,11 +748,11 @@ trait Infer { false } - private def isMoreSpecificValueType(tpe1: Type, tpe2: Type, undef1: List[Symbol], undef2: List[Symbol]): Boolean = (tpe1, tpe2) match { + private def isAsSpecificValueType(tpe1: Type, tpe2: Type, undef1: List[Symbol], undef2: List[Symbol]): Boolean = (tpe1, tpe2) match { case (PolyType(tparams1, rtpe1), _) => - isMoreSpecificValueType(rtpe1, tpe2, undef1 ::: tparams1, undef2) + isAsSpecificValueType(rtpe1, tpe2, undef1 ::: tparams1, undef2) case (_, PolyType(tparams2, rtpe2)) => - isMoreSpecificValueType(tpe1, rtpe2, undef1, undef2 ::: tparams2) + isAsSpecificValueType(tpe1, rtpe2, undef1, undef2 ::: tparams2) case _ => existentialAbstraction(undef1, tpe1) <:< existentialAbstraction(undef2, tpe2) } @@ -1291,16 +1320,18 @@ trait Infer { /* -- Overload Resolution ---------------------------------------------- */ +/* def checkNotShadowed(pos: Position, pre: Type, best: Symbol, eligible: List[Symbol]) = if (!phase.erasedTypes) for (alt <- eligible) { - if (alt.owner != best.owner && alt.owner.isSubClass(best.owner)) + if (isProperSubClassOrObject(alt.owner, best.owner)) error(pos, "erroneous reference to overloaded definition,\n"+ "most specific definition is: "+best+best.locationString+" of type "+pre.memberType(best)+ ",\nyet alternative definition "+alt+alt.locationString+" of type "+pre.memberType(alt)+ "\nis defined in a subclass") } +*/ /** Assign tree the symbol and type of the alternative which * matches prototype pt, if it exists. @@ -1310,6 +1341,7 @@ trait Infer { def inferExprAlternative(tree: Tree, pt: Type): Unit = tree.tpe match { case OverloadedType(pre, alts) => tryTwice { var alts1 = alts filter (alt => isWeaklyCompatible(pre.memberType(alt), pt)) + val applicable = alts1 var secondTry = false if (alts1.isEmpty) { alts1 = alts @@ -1346,9 +1378,9 @@ trait Infer { setError(tree) } } else { - val applicable = alts1 filter (alt => - global.typer.infer.isWeaklyCompatible(pre.memberType(alt), pt)) - checkNotShadowed(tree.pos, pre, best, applicable) +// val applicable = alts1 filter (alt => +// global.typer.infer.isWeaklyCompatible(pre.memberType(alt), pt)) +// checkNotShadowed(tree.pos, pre, best, applicable) tree.setSymbol(best).setType(pre.memberType(best)) } } @@ -1387,7 +1419,7 @@ trait Infer { setError(tree) () } else { - checkNotShadowed(tree.pos, pre, best, applicable) +// checkNotShadowed(tree.pos, pre, best, applicable) tree.setSymbol(best).setType(pre.memberType(best)) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 3a7880f326..325ed5f8f1 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -286,6 +286,16 @@ trait Namers { self: Analyzer => else if (owner.isTerm || owner.isPackageClass) List() else applicableTypeParams(owner.owner) ::: owner.typeParams + /** If no companion object for clazz exists yet, create one by applying `creator` to + * class definition tree. + * @return the companion object symbol. + */ + def ensureCompanionObject(tree: ClassDef, creator: ClassDef => Tree): Symbol = { + val m: Symbol = context.scope.lookupWithContext(tree.name.toTermName)(context.owner).filter(! _.isSourceMethod) + if (m.isModule && inCurrentScope(m) && (inIDE || currentRun.compiles(m))) m + else enterSyntheticSym(creator(tree)) + } + def enterSym(tree: Tree): Context = try { def finishWith(tparams: List[TypeDef]) { @@ -317,10 +327,7 @@ trait Namers { self: Analyzer => tree.symbol = enterClassSymbol(tree) finishWith(tparams) if ((mods.flags & CASE) != 0) { - var m: Symbol = context.scope.lookupWithContext(tree.name.toTermName)(context.owner).filter(! _.isSourceMethod) - if (!(m.isModule && inCurrentScope(m) && (inIDE || currentRun.compiles(m)))) { - m = enterSyntheticSym(caseModuleDef(tree)) - } + val m = ensureCompanionObject(tree, caseModuleDef) caseClassOfModuleClass(m.moduleClass) = tree } case tree @ ModuleDef(mods, name, _) => diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index 80794f6b61..84bddd5f97 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -133,11 +133,16 @@ trait Unapplies { self: Analyzer => /** The module corresponding to a case class; without any member definitions */ - def caseModuleDef(cdef: ClassDef): ModuleDef = atPos(cdef.pos) { - var parents = List(gen.scalaScalaObjectConstr) - if (!(cdef.mods hasFlag ABSTRACT) && cdef.tparams.isEmpty && constrParamss(cdef).length == 1) - parents = gen.scalaFunctionConstr(constrParamss(cdef).head map (_.tpt), - Ident(cdef.name)) :: parents + def caseModuleDef(cdef: ClassDef): ModuleDef = + companionModuleDef( + cdef, + if (!(cdef.mods hasFlag ABSTRACT) && cdef.tparams.isEmpty && constrParamss(cdef).length == 1) + List(gen.scalaFunctionConstr(constrParamss(cdef).head map (_.tpt), Ident(cdef.name)), + gen.scalaScalaObjectConstr) + else + List(gen.scalaScalaObjectConstr)) + + def companionModuleDef(cdef: ClassDef, parents: List[Tree]): ModuleDef = atPos(cdef.pos) { ModuleDef( Modifiers(cdef.mods.flags & AccessFlags | SYNTHETIC, cdef.mods.privateWithin), cdef.name.toTermName, diff --git a/src/library/scala/runtime/BoxesRunTime.java b/src/library/scala/runtime/BoxesRunTime.java index 89b141f71f..7b8d6bb672 100644 --- a/src/library/scala/runtime/BoxesRunTime.java +++ b/src/library/scala/runtime/BoxesRunTime.java @@ -42,6 +42,8 @@ public class BoxesRunTime { /* BOXING ... BOXING ... BOXING ... BOXING ... BOXING ... BOXING ... BOXING ... BOXING */ + // for 2.8: change to valueOf methods. + private static int charLowBound = 0; private static int charUpBound = 255; private static Character[] charCache = new Character[charUpBound - charLowBound + 1]; diff --git a/test/files/neg/implicits.check b/test/files/neg/implicits.check index 409d6ce6a7..b84586fc16 100644 --- a/test/files/neg/implicits.check +++ b/test/files/neg/implicits.check @@ -2,10 +2,9 @@ implicits.scala:21: error: type mismatch; found : Pos required: ?{val +: ?} Note that implicit conversions are not applicable because they are ambiguous: - most specific definition is: method pos2int in object Super of type (Pos)int - yet alternative definition method any2plus in object Sub of type (Any)Sub.Plus - is defined in a subclass. - Both definitions are possible conversion functions from Pos to ?{val +: ?} + both method any2plus in object Sub of type (Any)Sub.Plus + and method pos2int in object Super of type (Pos)int + are possible conversion functions from Pos to ?{val +: ?} f(p+1) ^ one error found diff --git a/test/files/neg/overload.check b/test/files/neg/overload.check index 5f7644eda7..760702778b 100644 --- a/test/files/neg/overload.check +++ b/test/files/neg/overload.check @@ -1,7 +1,7 @@ -overload.scala:10: error: erroneous reference to overloaded definition, -most specific definition is: method f in class C of type (int)Unit, -yet alternative definition method f in class D of type (Any)Unit -is defined in a subclass +overload.scala:10: error: ambiguous reference to overloaded definition, +both method f in class D of type (Any)Unit +and method f in class C of type (int)Unit +match argument types (Int) (new D).f(1) ^ one error found -- cgit v1.2.3