From 11bcf8ef29e894298b16d89fb58c73adc87188cf Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 25 Jan 2007 13:51:15 +0000 Subject: fsee message for 9732 --- .../scala/tools/nsc/typechecker/Infer.scala | 28 +++++++------ .../scala/tools/nsc/typechecker/RefChecks.scala | 46 ++++++++++++---------- .../scala/tools/nsc/typechecker/Typers.scala | 41 ++++++++++++------- src/library/scala/util/parsing/Parsers.scala | 4 +- test/files/pos/bug296.scala | 3 ++ test/files/pos/bug892.scala | 14 +++++++ 6 files changed, 86 insertions(+), 50 deletions(-) create mode 100644 test/files/pos/bug296.scala create mode 100644 test/files/pos/bug892.scala diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 63b59f01cb..983e72c75f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -243,6 +243,12 @@ trait Infer requires Analyzer { ";\n found : " + found.toLongString + "\n required: " + req } + def typeErrorMsg(found: Type, req: Type) = + "type mismatch" + foundReqMsg(found, req) + + (if (!(found.resultType eq found) && isWeaklyCompatible(found.resultType, req)) + "\n possible cause: missing arguments for method or constructor" + else "") + def error(pos: PositionType, msg: String): unit = context.error(pos, msg) @@ -251,15 +257,12 @@ trait Infer requires Analyzer { setError(tree) } - def typeError(pos: PositionType, found: Type, req: Type): unit = + def typeError(pos: PositionType, found: Type, req: Type) { if (!found.isErroneous && !req.isErroneous) { - error(pos, - "type mismatch" + foundReqMsg(found, req) + - (if (!(found.resultType eq found) && isWeaklyCompatible(found.resultType, req)) - "\n possible cause: missing arguments for method or constructor" - else "")) + error(pos, typeErrorMsg(found, req)) if (settings.explaintypes.value) explainTypes(found, req) } + } def typeErrorTree(tree: Tree, found: Type, req: Type): Tree = { typeError(tree.pos, found, req) @@ -574,12 +577,10 @@ trait Infer requires Analyzer { } /** error if arguments not within bounds. */ - def checkBounds(pos: PositionType, tparams: List[Symbol], - targs: List[Type], prefix: String): unit = - if (!isWithinBounds(NoPrefix, NoSymbol, tparams, targs)) { + def checkBounds(pos: PositionType, pre: Type, owner: Symbol, + tparams: List[Symbol], targs: List[Type], prefix: String) { + if (!isWithinBounds(pre, owner, tparams, targs)) { if (!(targs exists (.isErroneous)) && !(tparams exists (.isErroneous))) { - //Console.println("tparams = "+tparams+", bounds = "+tparams.map(.info)+", targs="+targs)//DEBUG - //withTypesExplained(isWithinBounds(NoPrefix, tparams, targs))//DEBUG error(pos, prefix + "type arguments " + targs.mkString("[", ",", "]") + " do not conform to " + tparams.head.owner + "'s type parameter bounds " + @@ -592,6 +593,7 @@ trait Infer requires Analyzer { () } } + } /** Substitite free type variables `undetparams' of polymorphic argument * expression `tree', given two prototypes `strictPt', and `lenientPt'. @@ -655,7 +657,7 @@ trait Infer requires Analyzer { val targs = methTypeArgs( undetparams, formalTypes(formals, argtpes.length), restpe, argtpes, pt, uninstantiated) - checkBounds(fn.pos, undetparams, targs, "inferred ") + checkBounds(fn.pos, NoPrefix, NoSymbol, undetparams, targs, "inferred ") //Console.println("UNAPPLY subst type "+undetparams+" to "+targs+" in "+fn+" ( "+args+ ")") val treeSubst = new TreeTypeSubstituter(undetparams, targs) treeSubst.traverse(fn) @@ -724,7 +726,7 @@ trait Infer requires Analyzer { def computeArgs = try { val targs = solve(tvars, undetparams, undetparams map varianceInType(restpe), true) - checkBounds(tree.pos, undetparams, targs, "inferred ") + checkBounds(tree.pos, NoPrefix, NoSymbol, undetparams, targs, "inferred ") new TreeTypeSubstituter(undetparams, targs).traverse(tree) } catch { case ex: NoInstance => diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 407068299b..8209665c15 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -486,24 +486,28 @@ abstract class RefChecks extends InfoTransform { case ClassDef(_, _, _, _, _) if isConcreteLocalCaseFactory(tree.symbol) => val clazz = tree.symbol val factory = clazz.caseFactory - assert(factory != NoSymbol, clazz) - def mkArgument(vparam: Symbol) = { - val id = Ident(vparam) - if (vparam.tpe.symbol == RepeatedParamClass) Typed(id, Ident(nme.WILDCARD_STAR.toTypeName)) - else id - } - val caseFactoryDef = - localTyper.typed { - atPos(tree.pos) { - DefDef( - factory, - vparamss => - (toConstructor(tree.pos, factory.tpe) /: vparamss) { - (fn, vparams) => Apply(fn, vparams map mkArgument) - }) - } + if (factory == NoSymbol) { + assert(clazz.owner.isTerm, clazz) + List(transform(tree)) + } else { + def mkArgument(vparam: Symbol) = { + val id = Ident(vparam) + if (vparam.tpe.symbol == RepeatedParamClass) Typed(id, Ident(nme.WILDCARD_STAR.toTypeName)) + else id } - List(transform(tree), caseFactoryDef) + val caseFactoryDef = + localTyper.typed { + atPos(tree.pos) { + DefDef( + factory, + vparamss => + (toConstructor(tree.pos, factory.tpe) /: vparamss) { + (fn, vparams) => Apply(fn, vparams map mkArgument) + }) + } + } + List(transform(tree), caseFactoryDef) + } case ValDef(_, _, _, _) => val tree1 = transform(tree); // important to do before forward reference check @@ -523,8 +527,8 @@ abstract class RefChecks extends InfoTransform { override def transform(tree: Tree): Tree = try { /* Check whether argument types conform to bounds of type parameters */ - def checkBounds(tparams: List[Symbol], argtps: List[Type]): unit = try { - typer.infer.checkBounds(tree.pos, tparams, argtps, ""); + def checkBounds(pre: Type, owner: Symbol, tparams: List[Symbol], argtps: List[Type]): unit = try { + typer.infer.checkBounds(tree.pos, pre, owner, tparams, argtps, ""); } catch { case ex: TypeError => unit.error(tree.pos, ex.getMessage()); } @@ -579,13 +583,13 @@ abstract class RefChecks extends InfoTransform { case TypeTree() => new TypeTraverser { def traverse(tp: Type): TypeTraverser = tp match { - case TypeRef(pre, sym, args) => checkBounds(sym.typeParams, args); this + case TypeRef(pre, sym, args) => checkBounds(pre, sym.owner, sym.typeParams, args); this case _ => this } } traverse tree.tpe case TypeApply(fn, args) => - checkBounds(fn.tpe.typeParams, args map (.tpe)) + checkBounds(NoPrefix, NoSymbol, fn.tpe.typeParams, args map (.tpe)) if (sym.isSourceMethod && sym.hasFlag(CASE)) result = toConstructor(tree.pos, tree.tpe) case Apply( diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index aa81ba6de3..6c5462196a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1525,7 +1525,7 @@ trait Typers requires Analyzer { case PolyType(tparams, restpe) if (tparams.length != 0) => if (tparams.length == args.length) { val targs = args map (.tpe) - checkBounds(tree.pos, tparams, targs, "") + checkBounds(tree.pos, NoPrefix, NoSymbol, tparams, targs, "") if (fun.symbol == Predef_classOf) { if (!targs.head.symbol.isClass || targs.head.symbol.isRefinementClass) error(args.head.pos, "class type required"); @@ -1939,15 +1939,19 @@ trait Typers requires Analyzer { } val lhs1 = typed(lhs, EXPRmode | LHSmode, WildcardType) val varsym = lhs1.symbol - if ((varsym ne null) && mayBeVarGetter(varsym)) { + if ((varsym ne null) && mayBeVarGetter(varsym)) lhs1 match { case Select(qual, name) => - typed( + return typed( Apply( Select(qual, nme.getterToSetter(name)) setPos lhs.pos, - List(rhs)) setPos tree.pos, mode, pt) + List(rhs)) setPos tree.pos, + mode, pt) + + case _ => + } - } else if ((varsym ne null) && (varsym.isVariable || varsym.isValue && phase.erasedTypes)) { + if ((varsym ne null) && (varsym.isVariable || varsym.isValue && phase.erasedTypes)) { val rhs1 = typed(rhs, lhs1.tpe) copy.Assign(tree, lhs1, rhs1) setType UnitClass.tpe } else { @@ -2391,16 +2395,23 @@ trait Typers requires Analyzer { val tc = newTyper(context.makeImplicit(reportAmbiguous)) - def ambiguousError(info1: ImplicitInfo, info2: ImplicitInfo, - pre1: String, pre2: String, trailer: String) = - error( - pos, - "ambiguous implicit value:\n "+ + def ambiguousImplicitError(info1: ImplicitInfo, info2: ImplicitInfo, + pre1: String, pre2: String, trailer: String) = { + val coreMsg = pre1+" "+info1.sym+info1.sym.locationString+" of type "+info1.tpe+"\n "+ pre2+" "+info2.sym+info2.sym.locationString+" of type "+info2.tpe+"\n "+ - trailer+ - (if (isView) "are possible conversion functions from "+ pt.typeArgs(0)+" to "+pt.typeArgs(1) - else "match expected type "+pt)) + trailer + error(pos, + if (isView) { + val found = pt.typeArgs(0) + val req = pt.typeArgs(1) + typeErrorMsg(found, req)+ + "\nNote that implicit conversions are not applicable because they are ambiguous:\n "+ + coreMsg+"are possible conversion functions from "+ found+" to "+req + } else { + "ambiguous implicit values:\n "+coreMsg + "match expected type "+pt + }) + } /** Search list of implicit info lists for one matching prototype * pt. If found return a tree from found implicit info @@ -2439,10 +2450,10 @@ trait Typers requires Analyzer { if (best == NoImplicitInfo) EmptyTree else { val competing = applicable dropWhile (alt => best == alt || improves(best, alt)) - if (!competing.isEmpty) ambiguousError(best, competing.head, "both", "and", "") + if (!competing.isEmpty) ambiguousImplicitError(best, competing.head, "both", "and", "") for (val alt <- applicable) if (alt.sym.owner != best.sym.owner && isSubClassOrObject(alt.sym.owner, best.sym.owner)) { - ambiguousError(best, alt, + ambiguousImplicitError(best, alt, "most specific definition is:", "yet alternative definition ", "is defined in a subclass.\n Both definitions ") diff --git a/src/library/scala/util/parsing/Parsers.scala b/src/library/scala/util/parsing/Parsers.scala index b016d0b6d1..6bc3f4a3ba 100644 --- a/src/library/scala/util/parsing/Parsers.scala +++ b/src/library/scala/util/parsing/Parsers.scala @@ -11,7 +11,9 @@ package scala.util.parsing -/** This class ... +/** Documentation for this class is currently missing. + * However, the Scala By Examples document contains a + * chapter on combinator parsing that comes close. * * @author Burak Emir * @version 1.0 diff --git a/test/files/pos/bug296.scala b/test/files/pos/bug296.scala new file mode 100644 index 0000000000..0c267a307e --- /dev/null +++ b/test/files/pos/bug296.scala @@ -0,0 +1,3 @@ +object Bug { + def foo (l: => String) : String = 12 match { case _ => l} +} diff --git a/test/files/pos/bug892.scala b/test/files/pos/bug892.scala new file mode 100644 index 0000000000..41da7095bd --- /dev/null +++ b/test/files/pos/bug892.scala @@ -0,0 +1,14 @@ +package test; +object Test { + trait Core { + abstract class Visitor[T <: Visitor[T]]; + trait HasVisitor { + def visit[T <: Visitor[T]](initial : T) : T; + } + } + trait Ext extends Core { + class Foo { + def visit[T <: Visitor[T]](initial : T) : T = initial; + } + } +} -- cgit v1.2.3