diff options
author | Martin Odersky <odersky@gmail.com> | 2009-10-07 14:10:34 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2009-10-07 14:10:34 +0000 |
commit | 9f121f57e034a7feb07bad7f67403f3ac75b46d4 (patch) | |
tree | dd68aed8983422a39dbc867397762a7bc5e5a9f8 /src/compiler/scala/tools/nsc/typechecker/Typers.scala | |
parent | ad62d9f8b00d328c099268366ae05c5122915fa6 (diff) | |
download | scala-9f121f57e034a7feb07bad7f67403f3ac75b46d4.tar.gz scala-9f121f57e034a7feb07bad7f67403f3ac75b46d4.tar.bz2 scala-9f121f57e034a7feb07bad7f67403f3ac75b46d4.zip |
Fixed #1000, #2060
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Typers.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 106 |
1 files changed, 61 insertions, 45 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 52f4952060..df17dcc416 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -225,27 +225,6 @@ trait Typers { self: Analyzer => } } - /** Infer an implicit conversion (``view'') that makes a member available. - * @param tree The tree which needs to be converted. - * @param from The source type of the conversion - * @param name The name of the member that needs to be available - * @param tp The expected type of the member that needs to be available - */ - def inferView(tree: Tree, from: Type, name: Name, tp: Type): Tree = { - val to = refinedType(List(WildcardType), NoSymbol) - var psym = if (name.isTypeName) to.typeSymbol.newAbstractType(tree.pos, name) - else to.typeSymbol.newValue(tree.pos, name) - psym = to.decls enter psym - psym setInfo tp - try { - inferView(tree, from, to, true) - } catch { - case ex: AssertionError => - println("inverView "+tree+", from = "+from+", name = "+name+" tp = "+tp) - throw ex - } - } - import infer._ private var namerCache: Namer = null @@ -604,10 +583,23 @@ trait Typers { self: Analyzer => (checkAccessible(tree, sym, pre, site), pre) } + /** Is `sym` defined in package object of package `pkg`? + */ private def isInPackageObject(sym: Symbol, pkg: Symbol) = - pkg.isPackageClass && - sym.owner.isPackageObjectClass && - sym.owner.owner == pkg + pkg.isPackageClass && { + sym.alternatives forall { sym => + !sym.owner.isPackage && { + sym.owner.isPackageObjectClass && + sym.owner.owner == pkg || + pkg.isInitialized && { + // need to be careful here to not get a cyclic reference during bootstrap + val pkgobj = pkg.info.member(nme.PACKAGEkw) + pkgobj.isInitialized && + (pkgobj.info.member(sym.name).alternatives contains sym) + } + } + } + } /** Post-process an identifier or selection node, performing the following: * 1. Check that non-function pattern expressions are stable @@ -995,33 +987,58 @@ trait Typers { self: Analyzer => adapt(tree, mode, pt) } - /** - * @param qual ... - * @param name ... - * @param tp ... - * @return ... - */ - def adaptToMember(qual: Tree, name: Name, tp: Type): Tree = { + def adaptToMember(qual: Tree, searchTemplate: Type): Tree = { val qtpe = qual.tpe.widen if (qual.isTerm && ((qual.symbol eq null) || !qual.symbol.isTerm || qual.symbol.isValue) && - phase.id <= currentRun.typerPhase.id && !qtpe.isError && !tp.isError && + phase.id <= currentRun.typerPhase.id && !qtpe.isError && qtpe.typeSymbol != NullClass && qtpe.typeSymbol != NothingClass && qtpe != WildcardType && context.implicitsEnabled) { // don't try to adapt a top-level type that's the subject of an implicit search // this happens because, if isView, typedImplicit tries to apply the "current" implicit value to // a value that needs to be coerced, so we check whether the implicit value has an `apply` method // (if we allow this, we get divergence, e.g., starting at `conforms` during ant quick.bin) // note: implicit arguments are still inferred (this kind of "chaining" is allowed) - val coercion = inferView(qual, qtpe, name, tp) + val coercion = inferView(qual, qtpe, searchTemplate, true) if (coercion != EmptyTree) typedQualifier(atPos(qual.pos)(Apply(coercion, List(qual)))) - else qual - } else qual + else + qual + } else { + qual + } } + /** Try to apply an implicit conversion to `qual' to that it contains + * a method `name` which can be applied to arguments `args' with expected type `pt'. + * If `pt' is defined, there is a fallback to try again with pt = ?. + * This helps avoiding propagating result information to far and solves + * #1756. + * If no conversion is found, return `qual' unchanged. + * + */ + def adaptToArguments(qual: Tree, name: Name, args: List[Tree], pt: Type): Tree = { + def doAdapt(restpe: Type) = + //util.trace("adaptToArgs "+qual+", name = "+name+", argtpes = "+(args map (_.tpe))+", pt = "+pt+" = ") + adaptToMember(qual, HasMethodMatching(name, args map (_.tpe), restpe)) + if (pt != WildcardType) { + silent(_ => doAdapt(pt)) match { + case result: Tree if result != qual => + result + case _ => + if (settings.debug.value) log("fallback on implicits in adaptToArguments: "+qual+" . "+name) + doAdapt(WildcardType) + } + } else + doAdapt(pt) + } + + /** Try to apply an implicit conversion to `qual' to that it contains a + * member `name` of arbitrary type. + * If no conversion is found, return `qual' unchanged. + */ def adaptToName(qual: Tree, name: Name) = if (member(qual, name)(context.owner) != NoSymbol) qual - else adaptToMember(qual, name, WildcardType) + else adaptToMember(qual, HasMember(name)) private def typePrimaryConstrBody(clazz : Symbol, cbody: Tree, tparams: List[Symbol], enclTparams: List[Symbol], vparamss: List[List[ValDef]]): Tree = { // XXX: see about using the class's symbol.... @@ -2997,19 +3014,18 @@ trait Typers { self: Analyzer => } } if (errorInResult(fun) || (args exists errorInResult)) { + if (printTypings) println("second try for: "+fun+" and "+args) val Select(qual, name) = fun val args1 = tryTypedArgs(args, argMode(fun, mode), ex) val qual1 = - if ((args1 ne null) && !pt.isError) { - def templateArgType(arg: Tree) = - new BoundedWildcardType(mkTypeBounds(arg.tpe, AnyClass.tpe)) - val dummyMethod = new TermSymbol(NoSymbol, NoPosition, "typer$dummy") - adaptToMember(qual, name, MethodType(dummyMethod.newSyntheticValueParams(args1 map templateArgType), pt)) - } else qual + if ((args1 ne null) && !pt.isError) adaptToArguments(qual, name, args1, pt) + else qual if (qual1 ne qual) { val tree1 = Apply(Select(qual1, name) setPos fun.pos, args1) setPos tree.pos return typed1(tree1, mode | SNDTRYmode, pt) } + } else if (printTypings) { + println("no second try for "+fun+" and "+args+" because error not in result:"+ex.pos+"!="+tree.pos) } reportTypeError(tree.pos, ex) setError(tree) @@ -3774,10 +3790,10 @@ trait Typers { self: Analyzer => tree.tpe = null if (tree.hasSymbol) tree.symbol = NoSymbol } - if (printTypings) println("typing "+tree+", "+context.undetparams+(mode & TYPEPATmode)); //DEBUG + if (printTypings) println("typing "+tree+", pt = "+pt+", undetparams = "+context.undetparams+", implicits-enabled = "+context.implicitsEnabled+", silent = "+context.reportGeneralErrors); //DEBUG var tree1 = if (tree.tpe ne null) tree else typed1(tree, mode, dropExistential(pt)) - if (printTypings) println("typed "+tree1+":"+tree1.tpe+", "+context.undetparams+", pt = "+pt); //DEBUG + if (printTypings) println("typed "+tree1+":"+tree1.tpe+(if (isSingleType(tree1.tpe)) " with underlying "+tree1.tpe.widen else "")+", undetparams = "+context.undetparams+", pt = "+pt); //DEBUG tree1.tpe = addAnnotations(tree1, tree1.tpe) @@ -3791,7 +3807,7 @@ trait Typers { self: Analyzer => case ex: ControlException => throw ex case ex: TypeError => tree.tpe = null - //Console.println("caught "+ex+" in typed");//DEBUG + if (printTypings) println("caught "+ex+" in typed: "+tree);//DEBUG reportTypeError(tree.pos, ex) setError(tree) case ex: Exception => |