summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2009-10-07 14:10:34 +0000
committerMartin Odersky <odersky@gmail.com>2009-10-07 14:10:34 +0000
commit9f121f57e034a7feb07bad7f67403f3ac75b46d4 (patch)
treedd68aed8983422a39dbc867397762a7bc5e5a9f8 /src/compiler
parentad62d9f8b00d328c099268366ae05c5122915fa6 (diff)
downloadscala-9f121f57e034a7feb07bad7f67403f3ac75b46d4.tar.gz
scala-9f121f57e034a7feb07bad7f67403f3ac75b46d4.tar.bz2
scala-9f121f57e034a7feb07bad7f67403f3ac75b46d4.zip
Fixed #1000, #2060
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Scanners.scala4
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala9
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala103
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala106
5 files changed, 157 insertions, 67 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
index 689c0d420e..570bb1f0c9 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
@@ -544,6 +544,10 @@ trait Scanners {
nextChar()
if (ch == '\"') {
nextChar()
+ while (ch == '\"') {
+ putChar('\"')
+ nextChar()
+ }
token = STRINGLIT
setStrVal()
} else {
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
index c562b7ed09..8579622f3c 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
@@ -204,6 +204,8 @@ abstract class SymbolLoaders {
// or treat as abstractions. For now the symbol in the package module takes precedence.
for (existing <- owner.info.decl(member.name).alternatives)
owner.info.decls.unlink(existing)
+ }
+ for (member <- m.info.decls.iterator) {
owner.info.decls.enter(member)
}
}
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index 9dfe0777ef..bacd4ef9dc 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -1485,8 +1485,14 @@ trait Symbols {
compose(List(kindString,
if (isClassConstructor) owner.simpleName.decode+idString else nameString))
+ /** If owner is a package object, its owner, else the normal owner.
+ */
+ def ownerSkipPackageObject =
+ if (owner.isPackageObjectClass) owner.owner else owner
+
/** String representation of location. */
- def locationString: String =
+ def locationString: String = {
+ val owner = ownerSkipPackageObject
if (owner.isClass &&
((!owner.isAnonymousClass &&
!owner.isRefinementClass &&
@@ -1494,6 +1500,7 @@ trait Symbols {
!owner.isRoot &&
!owner.isEmptyPackageClass) || settings.debug.value))
" in " + owner else ""
+ }
/** String representation of symbol's definition following its name */
final def infoString(tp: Type): String = {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index d2498741f3..e9ca2dd7c5 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -27,7 +27,7 @@ self: Analyzer =>
import global._
import definitions._
- final val traceImplicits = false
+ def traceImplicits = printTypings
var implicitTime = 0L
var inscopeSucceed = 0L
@@ -121,6 +121,59 @@ self: Analyzer =>
/** A sentinel indicating no implicit was found */
val NoImplicitInfo = new ImplicitInfo(null, NoType, NoSymbol)
+ /** A constructor for types ?{ name: tp }, used in infer view to member
+ * searches.
+ */
+ def memberWildcardType(name: Name, tp: Type) = {
+ val result = refinedType(List(WildcardType), NoSymbol)
+ var psym = if (name.isTypeName) result.typeSymbol.newAbstractType(NoPosition, name)
+ else result.typeSymbol.newValue(NoPosition, name)
+ psym setInfo tp
+ result.decls enter psym
+ result
+ }
+
+ /** An extractor for types of the form ? { name: ? }
+ */
+ object HasMember {
+ def apply(name: Name): Type = memberWildcardType(name, WildcardType)
+ def unapply(pt: Type): Option[Name] = pt match {
+ case RefinedType(List(WildcardType), decls) =>
+ decls.toList match {
+ case List(sym) if (sym.tpe == WildcardType) => Some(sym.name)
+ case _ => None
+ }
+ case _ =>
+ None
+ }
+ }
+
+ /** An extractor for types of the form ? { name: (? >: argtpe <: Any*)restp }
+ */
+ object HasMethodMatching {
+ def apply(name: Name, argtpes: List[Type], restpe: Type): Type = {
+ def templateArgType(argtpe: Type) =
+ new BoundedWildcardType(mkTypeBounds(argtpe, AnyClass.tpe))
+ val dummyMethod = new TermSymbol(NoSymbol, NoPosition, "typer$dummy")
+ val mtpe = MethodType(dummyMethod.newSyntheticValueParams(argtpes map templateArgType), restpe)
+ memberWildcardType(name, mtpe)
+ }
+ def unapply(pt: Type): Option[(Name, List[Type], Type)] = pt match {
+ case RefinedType(List(WildcardType), decls) =>
+ decls.toList match {
+ case List(sym) =>
+ sym.tpe match {
+ case MethodType(params, restpe)
+ if (params forall (_.tpe.isInstanceOf[BoundedWildcardType])) =>
+ Some((sym.name, params map (_.tpe.bounds.lo), restpe))
+ case _ => None
+ }
+ case _ => None
+ }
+ case _ => None
+ }
+ }
+
/** 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.
* @param pt The original expected type of the implicit.
@@ -291,16 +344,38 @@ self: Analyzer =>
*/
val wildPt = approximate(pt)
- //if (traceImplicits) println("typed impl for "+wildPt+"? "+info.name+":"+info.tpe+"/"+undetParams)
- if (isPlausiblyCompatible(info.tpe, wildPt) &&
- isCompatible(depoly(info.tpe), wildPt) &&
- isStable(info.pre)) {
+ /** Does type `tp' match wildPt?
+ * This is the case if either `wildPt' is a HasMethodMatching type
+ * and `tp' has a method matching wildPt, or otherwise if
+ * `tp' stripped of universal quantifiers is compatible with `wildPt'.
+ */
+ def matchesWildPt(tp: Type) = wildPt match {
+ case HasMethodMatching(name, argtpes, restpe) =>
+ (tp.member(name) filter (m => isApplicableSafe(List(), m.tpe, argtpes, restpe))) != NoSymbol
+ case _ =>
+ isCompatible(depoly(tp), wildPt)
+ }
+
+ /** Does type `tp' match prototype `pt'?
+ * This is the case if either `pt' is a HasMethodMatching type
+ * and `tp' has a member matching `pt', or otherwise if
+ * `tp' is compatible with `pt'.
+ */
+ def matchesPt(tp: Type, pt: Type) = pt match {
+ case HasMethodMatching(name, argtpes, restpe) =>
+ (tp.member(name) filter (m => isApplicableSafe(undetParams, m.tpe, argtpes, restpe))) != NoSymbol
+ case _ =>
+ isCompatible(tp, pt)
+ }
+
+ if (traceImplicits) println("typed impl for "+wildPt+"? "+info.name+":"+depoly(info.tpe)+"/"+undetParams+"/"+isPlausiblyCompatible(info.tpe, wildPt)+"/"+matchesWildPt(info.tpe))
+ if (isPlausiblyCompatible(info.tpe, wildPt) && matchesWildPt(info.tpe) && isStable(info.pre)) {
val itree = atPos(tree.pos.focus) {
if (info.pre == NoPrefix) Ident(info.name)
else Select(gen.mkAttributedQualifier(info.pre), info.name)
}
- //if (traceImplicits) println("typed impl?? "+info.name+":"+info.tpe+" ==> "+itree+" with "+wildPt)
+ if (traceImplicits) println("typed impl?? "+info.name+":"+info.tpe+" ==> "+itree+" with pt = "+pt+", wildpt = "+wildPt)
def fail(reason: String): SearchResult = {
if (settings.XlogImplicits.value)
inform(itree+" is not a valid implicit value for "+pt+" because:\n"+reason)
@@ -333,7 +408,7 @@ self: Analyzer =>
if (itree2.tpe.isError) SearchFailure
else if (hasMatchingSymbol(itree1)) {
val tvars = undetParams map freshVar
- if (isCompatible(itree2.tpe, pt.instantiateTypeParams(undetParams, tvars))) {
+ if (matchesPt(itree2.tpe, pt.instantiateTypeParams(undetParams, tvars))) {
if (traceImplicits) println("tvars = "+tvars+"/"+(tvars map (_.constr)))
val targs = solvedTypes(tvars, undetParams, undetParams map varianceInType(pt),
false, lubDepth(List(itree2.tpe, pt)))
@@ -670,20 +745,6 @@ self: Analyzer =>
mot(tp)
}
- /** An extractor for types of the form ? { name: ? }
- */
- object WildcardName {
- def unapply(pt: Type): Option[Name] = pt match {
- case RefinedType(List(WildcardType), decls) =>
- decls.toList match {
- case List(sym) if (sym.tpe == WildcardType) => Some(sym.name)
- case _ => None
- }
- case _ =>
- None
- }
- }
-
/** The result of the implicit search:
* First search implicits visible in current context.
* If that fails, search implicits in expected type `pt`.
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 =>