diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/Settings.scala | 3 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Symbols.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Contexts.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Infer.scala | 16 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Namers.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 317 | ||||
-rw-r--r-- | test/files/neg/faculty.check | 4 | ||||
-rwxr-xr-x | test/files/neg/faculty.scala | 5 | ||||
-rw-r--r-- | test/files/neg/imp2.check | 7 | ||||
-rwxr-xr-x | test/files/neg/imp2.scala | 19 | ||||
-rw-r--r-- | test/files/neg/viewtest.check | 7 | ||||
-rwxr-xr-x | test/files/neg/viewtest.scala | 116 | ||||
-rwxr-xr-x | test/files/pos/imp2.scala | 5 | ||||
-rw-r--r-- | test/files/pos/viewtest2.scala | 2 |
14 files changed, 348 insertions, 161 deletions
diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala index e717851b12..d6f86f593f 100644 --- a/src/compiler/scala/tools/nsc/Settings.scala +++ b/src/compiler/scala/tools/nsc/Settings.scala @@ -89,6 +89,7 @@ class Settings(error: String => unit) { val log = PhasesSetting ("-log", "Log operations in") val version = BooleanSetting("-version", "Print product version and exit") val help = BooleanSetting("-help", "Print a synopsis of standard options") +// val showPhases = BooleanSetting("-showphases", "Print a synopsis of compiler phases") val inline = BooleanSetting("-Xinline", "Perform inlining when possible") val Xshowcls = StringSetting ("-Xshowcls", "class", "Show class info", "") @@ -190,7 +191,7 @@ class Settings(error: String => unit) { * (the empty list, unless set) */ case class PhasesSetting(name: String, descr: String) - extends Setting(name, descr + " <phases> (see below)") { + extends Setting(name, descr + " <phase>") { // (see -showphases)") { var value: List[String] = List() def tryToSet(args: List[String]): List[String] = args match { diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index 2ba86159d8..bf2685d466 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -575,8 +575,8 @@ trait Symbols requires SymbolTable { * case class factory */ final def linkedClass: Symbol = { - if (owner.isPackageClass) - owner.info.decl(name.toTypeName).suchThat(sym => sym.rawInfo ne NoType) + if (this != NoSymbol && owner.isPackageClass) + owner.info.decl(name.toTypeName).suchThat(sym => sym.rawInfo ne NoType) else NoSymbol; } diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index d4833ba155..11d2aa2a3e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -340,5 +340,7 @@ trait Contexts requires Analyzer { case class ImplicitInfo(val name: Name, val tpe: Type, val sym: Symbol); + val NoImplicitInfo = ImplicitInfo(null, null, null) + case class ImportType(expr: Tree) extends Type; } diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 9cabd952f0..22143b8b78 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -423,6 +423,13 @@ trait Infer requires Analyzer { false } + /** Is type `tpe1' a strictly better alternative than type `ftpe2'? */ + def isStrictlyBetter(tpe1: Type, tpe2: Type) = { + def isNullary(tpe: Type) = tpe.paramSectionCount == 0 || tpe.paramTypes.isEmpty + isNullary(tpe1) && !isNullary(tpe2) || + specializes(tpe1, tpe2) && !specializes(tpe2, tpe1) + } + /** error if arguments not within bounds. */ def checkBounds(pos: int, tparams: List[Symbol], targs: List[Type], prefix: String): unit = if (!isWithinBounds(tparams, targs)) { @@ -598,8 +605,7 @@ trait Infer requires Analyzer { val tp2 = pre.memberType(sym2); (tp2 == ErrorType || !global.typer.infer.isCompatible(tp2, pt) && global.typer.infer.isCompatible(tp1, pt) || - ((tp2.paramSectionCount > 0 && !tp2.paramTypes.isEmpty) && (tp1.paramSectionCount == 0 || tp1.paramTypes.isEmpty)) || - specializes(tp1, tp2) && !specializes(tp2, tp1)) + isStrictlyBetter(tp1, tp2)) }) ); val best = ((NoSymbol: Symbol) /: alts1) ((best, alt) => @@ -636,15 +642,15 @@ trait Infer requires Analyzer { def inferMethodAlternative(tree: Tree, undetparams: List[Symbol], argtpes: List[Type], pt: Type): unit = tree.tpe match { case OverloadedType(pre, alts) => tryTwice { if (settings.debug.value) log("infer method alt " + tree.symbol + " with alternatives " + (alts map pre.memberType) + ", argtpes = " + argtpes + ", pt = " + pt); - val alts1 = alts filter (alt => isApplicable(undetparams, pre.memberType(alt), argtpes, pt)); + val applicable = alts filter (alt => isApplicable(undetparams, pre.memberType(alt), argtpes, pt)); def improves(sym1: Symbol, sym2: Symbol) = ( sym2 == NoSymbol || sym2.isError || ((sym1.owner isSubClass sym2.owner) && specializes(pre.memberType(sym1), pre.memberType(sym2))) ); - val best = ((NoSymbol: Symbol) /: alts1) ((best, alt) => + val best = ((NoSymbol: Symbol) /: applicable) ((best, alt) => if (improves(alt, best)) alt else best); - val competing = alts1 dropWhile (alt => best == alt || improves(best, alt)); + val competing = applicable dropWhile (alt => best == alt || improves(best, alt)); if (best == NoSymbol) { if (pt == WildcardType) { errorTree(tree, applyErrorMsg(tree, " cannot be applied to ", argtpes, pt)) diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index f6581950bd..bf5f278467 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -135,7 +135,7 @@ trait Namers requires Analyzer { val file = context.unit.source.getFile(); val clazz = c.asInstanceOf[ClassSymbol]; if (c.owner.isPackageClass) { - if (clazz.sourceFile != null && !clazz.sourceFile.equals(file)) { + if (settings.debug.value && clazz.sourceFile != null && !clazz.sourceFile.equals(file)) { System.err.println("SOURCE MISMATCH: " + clazz.sourceFile + " vs. " + file + " SYM=" + c); } clazz.sourceFile = file; diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 7d17f883d3..8e3716981e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -7,6 +7,7 @@ package scala.tools.nsc.typechecker import symtab.Flags._ +import util.HashSet import scala.tools.nsc.util.Position import scala.collection.mutable.{HashMap, ListBuffer} @@ -22,7 +23,7 @@ trait Typers requires Analyzer { var implcnt = 0 var impltime = 0l - final val xviews = false + final val xviews = true private val transformed = new HashMap[Tree, Tree] @@ -39,7 +40,7 @@ trait Typers requires Analyzer { object UnTyper extends Traverser { override def traverse(tree: Tree) = { if (tree != EmptyTree) tree.tpe = null; - if (tree.hasSymbol && tree.symbol.isError) tree.symbol = null; + if (tree.hasSymbol) tree.symbol = NoSymbol; super.traverse(tree) } } @@ -122,24 +123,20 @@ trait Typers requires Analyzer { /** Report a type error. * @param pos The position where to report the error * @param ex The exception that caused the error */ - def reportTypeError(pos: int, ex: TypeError): unit = { - val msg = ex match { - case CyclicReference(sym, info: TypeCompleter) => - info.tree match { - case ValDef(_, _, tpt, _) if (tpt.tpe == null) => - "recursive "+sym+" needs type" - case DefDef(_, _, _, _, tpt, _) if (tpt.tpe == null) => + def reportTypeError(pos: int, ex: TypeError): unit = ex match { + case CyclicReference(sym, info: TypeCompleter) => + context.unit.error(pos, + info.tree match { + case ValDef(_, _, tpt, _) if (tpt.tpe == null) => + "recursive "+sym+" needs type" + case DefDef(_, _, _, _, tpt, _) if (tpt.tpe == null) => (if (sym.owner.isClass && sym.owner.info.member(sym.name).hasFlag(OVERLOADED)) "overloaded " else "recursive ")+sym+" needs result type" - case _ => - ex.getMessage() - } - case _ => - ex.getMessage() - } - //if (settings.debug.value) ex.printStackTrace()//DEBUG - if (context.reportGeneralErrors) error(pos, msg) - else throw new TypeError(msg) + case _ => + ex.getMessage() + }) + case _ => + context.error(pos, ex.getMessage()) } /** Check that tree is a stable expression. @@ -1003,57 +1000,69 @@ trait Typers requires Analyzer { def typedArgs(args: List[Tree]) = List.mapConserve(args)(arg => typedArg(arg, WildcardType)) - def typedApply(fun: Tree, args: List[Tree]): Tree = fun.tpe match { - case OverloadedType(pre, alts) => - val args1 = typedArgs(args) - inferMethodAlternative(fun, context.undetparams, args1 map (.tpe.deconst), pt) - typedApply(adapt(fun, funmode, WildcardType), args1) - case MethodType(formals0, restpe) => - val formals = formalTypes(formals0, args.length) - if (formals.length != args.length) { - //System.out.println(""+formals.length+" "+args.length);//DEBUG - errorTree(tree, "wrong number of arguments for "+treeSymTypeMsg(fun)) - } else { - val tparams = context.undetparams - context.undetparams = List() - if (tparams.isEmpty) { - val args1 = List.map2(args, formals)(typedArg) - def ifPatternSkipFormals(tp: Type) = tp match { - case MethodType(_, rtp) if ((mode & PATTERNmode) != 0) => rtp - case _ => tp - } - constfold(copy.Apply(tree, fun, args1).setType(ifPatternSkipFormals(restpe))) - } else { - assert((mode & PATTERNmode) == 0); // this case cannot arise for patterns - val lenientTargs = protoTypeArgs(tparams, formals, restpe, pt) - val strictTargs = List.map2(lenientTargs, tparams)((targ, tparam) => - if (targ == WildcardType) tparam.tpe else targ) - def typedArgToPoly(arg: Tree, formal: Type): Tree = { - val lenientPt = formal.subst(tparams, lenientTargs) - val arg1 = typedArg(arg, lenientPt) - val argtparams = context.undetparams - context.undetparams = List() - if (!argtparams.isEmpty) { - val strictPt = formal.subst(tparams, strictTargs) - inferArgumentInstance(arg1, argtparams, strictPt, lenientPt) - } - arg1 - } - val args1 = List.map2(args, formals)(typedArgToPoly) - if (args1 exists (.tpe.isError)) setError(tree) - else { - if (settings.debug.value) log("infer method inst "+fun+", tparams = "+tparams+", args = "+args1.map(.tpe)+", pt = "+pt+", lobounds = "+tparams.map(.tpe.bounds.lo));//debug - val undetparams = inferMethodInstance(fun, tparams, args1, pt) - val result = typedApply(fun, args1) - context.undetparams = undetparams - result + def typedApply(fun0: Tree, args: List[Tree]): Tree = { + var fun = fun0; + if (fun.hasSymbol && (fun.symbol hasFlag OVERLOADED)) { + // preadapt symbol to number of arguments given + val argtypes = args map (arg => AllClass.tpe) + val pre = fun.symbol.tpe.prefix + val sym = fun.symbol filter (alt => + isApplicable(context.undetparams, pre.memberType(alt), argtypes, pt)) + if (sym != NoSymbol) + fun = adapt(fun setSymbol sym setType pre.memberType(sym), funmode, WildcardType) + } + fun.tpe match { + case OverloadedType(pre, alts) => + val args1 = typedArgs(args) + inferMethodAlternative(fun, context.undetparams, args1 map (.tpe.deconst), pt) + typedApply(adapt(fun, funmode, WildcardType), args1) + case MethodType(formals0, restpe) => + val formals = formalTypes(formals0, args.length) + if (formals.length != args.length) { + //System.out.println(""+formals.length+" "+args.length);//DEBUG + errorTree(tree, "wrong number of arguments for "+treeSymTypeMsg(fun)) + } else { + val tparams = context.undetparams + context.undetparams = List() + if (tparams.isEmpty) { + val args1 = List.map2(args, formals)(typedArg) + def ifPatternSkipFormals(tp: Type) = tp match { + case MethodType(_, rtp) if ((mode & PATTERNmode) != 0) => rtp + case _ => tp + } + constfold(copy.Apply(tree, fun, args1).setType(ifPatternSkipFormals(restpe))) + } else { + assert((mode & PATTERNmode) == 0); // this case cannot arise for patterns + val lenientTargs = protoTypeArgs(tparams, formals, restpe, pt) + val strictTargs = List.map2(lenientTargs, tparams)((targ, tparam) => + if (targ == WildcardType) tparam.tpe else targ) + def typedArgToPoly(arg: Tree, formal: Type): Tree = { + val lenientPt = formal.subst(tparams, lenientTargs) + val arg1 = typedArg(arg, lenientPt) + val argtparams = context.undetparams + context.undetparams = List() + if (!argtparams.isEmpty) { + val strictPt = formal.subst(tparams, strictTargs) + inferArgumentInstance(arg1, argtparams, strictPt, lenientPt) + } + arg1 + } + val args1 = List.map2(args, formals)(typedArgToPoly) + if (args1 exists (.tpe.isError)) setError(tree) + else { + if (settings.debug.value) log("infer method inst "+fun+", tparams = "+tparams+", args = "+args1.map(.tpe)+", pt = "+pt+", lobounds = "+tparams.map(.tpe.bounds.lo));//debug + val undetparams = inferMethodInstance(fun, tparams, args1, pt) + val result = typedApply(fun, args1) + context.undetparams = undetparams + result + } } } - } - case ErrorType => - setError(tree) - case _ => - errorTree(tree, ""+fun+" does not take parameters") + case ErrorType => + setError(tree) + case _ => + errorTree(tree, ""+fun+" does not take parameters") + } } def tryTypedArgs(args: List[Tree]) = { @@ -1072,31 +1081,25 @@ trait Typers requires Analyzer { } } + /** Try to apply function to arguments; if it does not work try to insert an implicit + * conversion + */ def tryTypedApply(fun: Tree, args: List[Tree]): Tree = { val reportGeneralErrors = context.reportGeneralErrors - val reportAmbiguousErrors = context.reportAmbiguousErrors try { context.reportGeneralErrors = false - context.reportAmbiguousErrors = false typedApply(fun, args) } catch { case ex: TypeError => val Select(qual, name) = fun - var qual1 = qual; - var args1 = tryTypedArgs(args) + val args1 = tryTypedArgs(args map UnTyper.apply) context.reportGeneralErrors = reportGeneralErrors - context.reportAmbiguousErrors = reportAmbiguousErrors - if (args1 != null && !args1.exists(.tpe.isError) && !pt.isError) { - qual1 = adaptToMember(qual, name, MethodType(args1 map (.tpe), pt)) - } - val args2 = args map UnTyper.apply; - val tree1 = - if (qual1 eq qual) Apply(UnTyper.apply(fun), args2) - else Apply(Select(UnTyper.apply(qual1), name) setPos fun.pos, args2) - typed1(tree1 setPos tree.pos, mode | SNDTRYmode, pt) + val qual1 = if (args1 == null || pt.isError) qual + else adaptToMember(qual, name, MethodType(args1 map (.tpe), pt)) + val tree1 = Apply(Select(qual1, name) setPos fun.pos, args map UnTyper.apply) setPos tree.pos + typed1(tree1, mode | SNDTRYmode, pt) } finally { context.reportGeneralErrors = reportGeneralErrors - context.reportAmbiguousErrors = reportAmbiguousErrors } } @@ -1211,8 +1214,11 @@ trait Typers requires Analyzer { if (impSym.tpe != NoType) { var impSym1 = NoSymbol var imports1 = imports.tail - def ambiguousImportError = ambiguousError( - "it is imported twice in the same scope by\n"+imports.head + "\nand "+imports1.head) + def ambiguousImport() = { + if (!(imports.head.qual.tpe =:= imports1.head.qual.tpe)) + ambiguousError( + "it is imported twice in the same scope by\n"+imports.head + "\nand "+imports1.head) + } while (!imports1.isEmpty && (!imports.head.isExplicitImport(name) || imports1.head.depth == imports.head.depth)) { @@ -1220,11 +1226,11 @@ trait Typers requires Analyzer { if (impSym1 != NoSymbol) { if (imports1.head.isExplicitImport(name)) { if (imports.head.isExplicitImport(name) || - imports1.head.depth != imports.head.depth) ambiguousImportError + imports1.head.depth != imports.head.depth) ambiguousImport() impSym = impSym1; imports = imports1 } else if (!imports.head.isExplicitImport(name) && - imports1.head.depth == imports.head.depth) ambiguousImportError + imports1.head.depth == imports.head.depth) ambiguousImport() } imports1 = imports1.tail } @@ -1455,14 +1461,6 @@ trait Typers requires Analyzer { // if function is overloaded, filter all alternatives that match // number of arguments and expected result type. if (settings.debug.value) log("trans app "+fun1+":"+fun1.symbol+":"+fun1.tpe+" "+args);//DEBUG - if (fun1.hasSymbol && (fun1.symbol hasFlag OVERLOADED)) { - val argtypes = args map (arg => AllClass.tpe) - val pre = fun1.symbol.tpe.prefix - val sym = fun1.symbol filter (alt => - isApplicable(context.undetparams, pre.memberType(alt), argtypes, pt)) - if (sym != NoSymbol) - fun1 = adapt(fun1 setSymbol sym setType pre.memberType(sym), funmode, WildcardType) - } if (util.Statistics.enabled) appcnt = appcnt + 1 if (xviews && fun1.isInstanceOf[Select] && @@ -1669,77 +1667,96 @@ trait Typers requires Analyzer { case _ => tp.isError } - private def typedImplicit(pos: int, info: ImplicitInfo, pt: Type, local: boolean): Tree = - if (isCompatible(depoly(info.tpe), pt) && !containsError(info.tpe)) { - var tree: Tree = EmptyTree + /** 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 isLocal Is implicit definition visible without prefix? + * @returns 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: int, info: ImplicitInfo, pt: Type, isLocal: boolean): Tree = + if (isCompatible(depoly(info.tpe), pt)) { + val tree = Ident(info.name) setPos pos def fail(reason: String, sym1: Symbol, sym2: Symbol): Tree = { if (settings.debug.value) - log(""+tree+" is not a valid implicit value because:\n"+reason + - sym1+" "+sym2); + log(""+tree+" is not a valid implicit value because:\n"+reason + sym1+" "+sym2); EmptyTree } - try { - tree = Ident(info.name) setPos pos - if (!local) tree setSymbol info.sym - tree = typed1(tree, EXPRmode, pt) - if (settings.debug.value) - log("typed implicit "+tree+":"+tree.tpe+", pt = "+pt);//debug - val tree1 = adapt(tree, EXPRmode, pt) - if (settings.debug.value) - log("adapted implicit "+tree.symbol+":"+tree1.tpe+" to "+pt);//debug - if (tree1.tpe != ErrorType && info.sym == tree.symbol) tree1 - else fail("syms differ: ", tree.symbol, info.sym) - } catch { + try { + if (!isLocal) tree setSymbol info.sym + val tree1 = typed1(tree, EXPRmode, pt) + if (settings.debug.value) log("typed implicit "+tree1+":"+tree1.tpe+", pt = "+pt); + val tree2 = adapt(tree1, EXPRmode, pt) + if (settings.debug.value) log("adapted implicit "+tree1.symbol+":"+tree2.tpe+" to "+pt); + if (!tree2.tpe.isError && info.sym == tree1.symbol) tree2 + else fail("syms differ: ", tree1.symbol, info.sym) + } catch { case ex: TypeError => fail(ex.getMessage(), NoSymbol, NoSymbol) - } + } } else EmptyTree + /** Infer implicit argument or view + * @param pos position for error reporting + * @param pt the expected type of the implicit + * @param isView are we searching for a view? (this affects the error message) + * @param reportAmbiguous should ambiguous errors be reported? False iff we search for a view + * to find out whether one type is coercible to another (@see isCoercible) + */ private def inferImplicit(pos: int, pt: Type, isView: boolean, reportAmbiguous: boolean): Tree = { if (util.Statistics.enabled) implcnt = implcnt + 1 val startTime = if (util.Statistics.enabled) System.currentTimeMillis() else 0l - def isBetter(sym1: Symbol, tpe1: Type, sym2: Symbol, tpe2: Type): boolean = ( - sym2.isError || - (sym1.owner != sym2.owner) && (sym1.owner isSubClass sym2.owner) && (tpe1 matches tpe2) - ) val tc = newTyper(context.makeImplicit(reportAmbiguous)) - def searchImplicit(implicitInfoss: List[List[ImplicitInfo]], local: boolean): Tree = { - var iss = implicitInfoss - var tree: Tree = EmptyTree - while (tree == EmptyTree && !iss.isEmpty) { - var is = iss.head - iss = iss.tail - while (!is.isEmpty) { - tree = tc.typedImplicit(pos, is.head, pt, local) - if (settings.debug.value) log("tested "+is.head.sym + is.head.sym.locationString+":"+is.head.tpe+"="+tree);//debug - val is0 = is - is = is.tail - if (tree != EmptyTree) { - while (!is.isEmpty) { - val tree1 = tc.typedImplicit(pos, is.head, pt, local) - if (tree1 != EmptyTree) { - if (isBetter(is.head.sym, tree1.tpe, is0.head.sym, tree.tpe)) - tree = tree1 - else if (!isBetter(is0.head.sym, tree.tpe, is.head.sym, tree1.tpe)) - error( - pos, - "ambiguous implicit value:\n" + - " both "+is0.head.sym + is0.head.sym.locationString+" of type "+tree.tpe + - "\n and "+is.head.sym + is.head.sym.locationString+" of type "+tree1.tpe + - (if (isView) - "\n are possible conversion functions from "+ - pt.typeArgs(0)+" to "+pt.typeArgs(1) - else - "\n match expected type "+pt)) - } - is = is.tail - } - } - } - } - tree + def ambiguousError(info1: ImplicitInfo, info2: ImplicitInfo) = + error( + pos, + "ambiguous implicit value:\n" + + " both "+info1.sym + info1.sym.locationString+" of type "+info1.tpe+ + "\n and "+info2.sym + info2.sym.locationString+" of type "+info2.tpe+ + (if (isView) "\n are possible conversion functions from "+ pt.typeArgs(0)+" to "+pt.typeArgs(1) + else "\n match expected type "+pt)) + + /** Search list of implicit info lists for one matching prototype `pt' + * If found return a tree from found implicit info which is typed with expected type `pt'. + * Otherwise return EmptyTree + * @param implicitInfoss The given list of lists of implicit infos + * @isLocal Is implicit definition visible without prefix? + * If this is the case then symbols in preceding lists shadow + * symbols of the same name in succeeding lists. + */ + def searchImplicit(implicitInfoss: List[List[ImplicitInfo]], isLocal: boolean): Tree = { + def isSubClassOrObject(sym1: Symbol, sym2: Symbol) = { + (sym1 isSubClass sym2) || + sym1.isModuleClass && sym2.isModuleClass && + (sym1.sourceModule.linkedClass isSubClass sym2.sourceModule.linkedClass) + } + def improves(info1: ImplicitInfo, info2: ImplicitInfo) = + (info2 == NoImplicitInfo) || + (info1 != NoImplicitInfo) && + isSubClassOrObject(info1.sym.owner, info2.sym.owner) && + isStrictlyBetter(info1.tpe, info2.tpe) + val shadowed = new HashSet[Name](8) + def isApplicable(info: ImplicitInfo): boolean = + !containsError(info.tpe) && + !(isLocal && shadowed.contains(info.name)) && + tc.typedImplicit(pos, info, pt, isLocal) != EmptyTree + def applicableInfos(is: List[ImplicitInfo]) = { + val result = is filter isApplicable + if (isLocal) + for (val i <- is) shadowed addEntry i.name + result + } + val applicable = List.flatten(implicitInfoss map applicableInfos) + val best = (NoImplicitInfo /: applicable) ((best, alt) => if (improves(alt, best)) alt else best) + val competing = applicable dropWhile (alt => best == alt || improves(best, alt)) + if (best == NoImplicitInfo) EmptyTree + else { + if (!competing.isEmpty) ambiguousError(best, competing.head) + tc.typedImplicit(pos, best, pt, isLocal) + } } def implicitsOfType(tp: Type): List[List[ImplicitInfo]] = { diff --git a/test/files/neg/faculty.check b/test/files/neg/faculty.check new file mode 100644 index 0000000000..1a1c65f853 --- /dev/null +++ b/test/files/neg/faculty.check @@ -0,0 +1,4 @@ +faculty.scala:3 error: recursive method faculty needs result type + def faculty(x: int) = if (x == 0) 1 else x * faculty(x - 1)
+ ^ +one error found diff --git a/test/files/neg/faculty.scala b/test/files/neg/faculty.scala new file mode 100755 index 0000000000..464033ef30 --- /dev/null +++ b/test/files/neg/faculty.scala @@ -0,0 +1,5 @@ +object Test { + + def faculty(x: int) = if (x == 0) 1 else x * faculty(x - 1) + +} diff --git a/test/files/neg/imp2.check b/test/files/neg/imp2.check new file mode 100644 index 0000000000..2daca73bf3 --- /dev/null +++ b/test/files/neg/imp2.check @@ -0,0 +1,7 @@ +imp2.scala:18 error: reference to f is ambiguous; +it is imported twice in the same scope by +import b.{_} +and import a.{_} + val x = f
+ ^ +one error found diff --git a/test/files/neg/imp2.scala b/test/files/neg/imp2.scala new file mode 100755 index 0000000000..20b3df5d91 --- /dev/null +++ b/test/files/neg/imp2.scala @@ -0,0 +1,19 @@ +abstract class C { + val f: int +} + +object A extends C { + val f = 1 +} + +object B extends C { + val f = 2 +} + +object Test { + val a: C = A; + val b: C = B; + import a._ + import b._ + val x = f +} diff --git a/test/files/neg/viewtest.check b/test/files/neg/viewtest.check new file mode 100644 index 0000000000..f7920de368 --- /dev/null +++ b/test/files/neg/viewtest.check @@ -0,0 +1,7 @@ +viewtest.scala:104 error: ambiguous implicit value: + both method view4 in object O of type [a](a)a + and method identity in object Predef of type [a](a)a + match expected type (test.Str) => test.Ordered[test.Str] + t = t insert Str(s) + ^ +one error found diff --git a/test/files/neg/viewtest.scala b/test/files/neg/viewtest.scala new file mode 100755 index 0000000000..deb6480983 --- /dev/null +++ b/test/files/neg/viewtest.scala @@ -0,0 +1,116 @@ +package test; + +/** A trait for totally ordered data. + */ +trait Ordered[+a] { + + /** Result of comparing `this' with operand `that'. + * returns `x' where + * x < 0 iff this < that + * x == 0 iff this == that + * x > 0 iff this > that + */ + def compareTo [b >: a <% Ordered[b]](that: b): int; + + def < [b >: a <% Ordered[b]](that: b): boolean = (this compareTo that) < 0; + + def > [b >: a <% Ordered[b]](that: b): boolean = (this compareTo that) > 0; + + def <= [b >: a <% Ordered[b]](that: b): boolean = (this compareTo that) <= 0; + + def >= [b >: a <% Ordered[b]](that: b): boolean = (this compareTo that) >= 0; +} + + +object O { + + implicit def view1(x: String): Ordered[String] = new Ordered[String] { + def compareTo [b >: String <% Ordered[b]](y: b): int = y match { + case y1: String => x compareTo y1; + case _ => -(y compareTo x) + } + } + implicit def view2(x: char): Ordered[char] = new Ordered[char] { + def compareTo [b >: char <% Ordered[b]](y: b): int = y match { + case y1: char => x - y1; + case _ => -(y compareTo x) + } + } + + implicit def view3[a <% Ordered[a]](x: List[a]): Ordered[List[a]] = + new Ordered[List[a]] { + def compareTo [b >: List[a] <% Ordered[b]](y: b): int = y match { + case y1: List[a] => compareLists(x, y1); + case _ => -(y compareTo x) + } + private def compareLists(xs: List[a], ys: List[a]): int = { + if (xs.isEmpty && ys.isEmpty) 0 + else if (xs.isEmpty) -1 + else if (ys.isEmpty) 1 + else { + val s = xs.head compareTo ys.head; + if (s != 0) s + else compareLists(xs.tail, ys.tail) + } + } + } + implicit def view4[a](x: a): a = x; +} + +trait Tree[+a <% Ordered[a]] { + def insert[b >: a <% Ordered[b]](x: b): Tree[b]; + def elements: List[a] +} + +object Empty extends Tree[All] { + def insert[b >: All <% Ordered[b]](x: b): Tree[b] = new Node(x, Empty, Empty); + def elements: List[All] = List(); +} + +class Node[a <% Ordered[a]](elem: a, l: Tree[a], r: Tree[a]) extends Tree[a] { + def insert[b >: a <% Ordered[b]](x: b): Tree[b] = + if (x == elem) this + else if (x < elem) new Node(elem, l insert x, r) + else new Node(elem, l, r insert x); + def elements: List[a] = + l.elements ::: List(elem) ::: r.elements +} + +case class Str(elem: String) extends Ordered[Str] { + def compareTo[b >: Str <% Ordered[b]](that: b): int = that match { + case that1: Str => this.elem compareTo that1.elem + case _ => -(that compareTo this) + } +} + +object Test { + import O._; + + private def toCharList(s: String): List[Char] = + if (s.length() == 0) List() + else s.charAt(0) :: toCharList(s.substring(1)); + + def main(args: Array[String]) = { + { + var t: Tree[String] = Empty; + for (val s <- args) { + t = t insert s + } + System.out.println(t.elements) + } + { + var t: Tree[Str] = Empty; + for (val s <- args) { + t = t insert Str(s) + } + System.out.println(t.elements) + } + { + var t: Tree[List[char]] = Empty; + for (val s <- args) { + t = t insert toCharList(s) + } + System.out.println(t.elements) + } + } +} diff --git a/test/files/pos/imp2.scala b/test/files/pos/imp2.scala new file mode 100755 index 0000000000..5460c60015 --- /dev/null +++ b/test/files/pos/imp2.scala @@ -0,0 +1,5 @@ +object Test { + import collection.mutable._ + import collection.mutable._ + val x = new HashMap +} diff --git a/test/files/pos/viewtest2.scala b/test/files/pos/viewtest2.scala index 1958696c1f..51df563633 100644 --- a/test/files/pos/viewtest2.scala +++ b/test/files/pos/viewtest2.scala @@ -54,8 +54,6 @@ object O { } } } - - implicit def view4[a](x: a): a = x; } trait Tree[+a <% Ordered[a]] { |