diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/icode/GenICode.scala | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Symbols.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Types.scala | 25 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Constructors.scala | 8 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Implicits.scala | 95 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Infer.scala | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 29 | ||||
-rw-r--r-- | test/files/neg/bug608.check | 2 | ||||
-rw-r--r-- | test/files/run/constrained-types.check | 8 |
9 files changed, 123 insertions, 50 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 3a4fa76891..52b8838c04 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -1426,6 +1426,7 @@ abstract class GenICode extends SubComponent { case Some(local) => local case None => val local = ctx.makeLocal(l.pos, definitions.AnyRefClass.typeConstructor, eqEqTempName.toString) + //assert(!l.pos.source.isEmpty, "bad position, unit = "+unit+", tree = "+l+", pos = "+l.pos.source) assert(l.pos.source.get == unit.source) assert(r.pos.source.get == unit.source) local.start = (l.pos).line.get diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index 021a3e1dbe..106b737672 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -342,6 +342,8 @@ trait Symbols { final def isRefinementClass = isClass && name == nme.REFINE_CLASS_NAME.toTypeName; // no lifting for refinement classes final def isModuleClass = isClass && hasFlag(MODULE) final def isPackageClass = isClass && hasFlag(PACKAGE) + final def isPackageObjectClass = isModuleClass && name.toTermName == nme.PACKAGEkw && owner.isPackageClass + final def definedInPackage = owner.isPackageClass || owner.isPackageObjectClass final def isRoot = isPackageClass && name == nme.ROOT.toTypeName final def isRootPackage = isPackage && name == nme.ROOTPKG final def isEmptyPackage = isPackage && name == nme.EMPTY_PACKAGE_NAME @@ -1357,6 +1359,8 @@ trait Symbols { override def toString(): String = if (isValueParameter && owner.isSetter) "parameter of setter "+owner.nameString + else if (isPackageObjectClass) + "package object "+nameString else compose(List(kindString, if (isClassConstructor) owner.simpleName.decode+idString else nameString)) diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index dab101a15f..9aa29a7395 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -1826,8 +1826,14 @@ A type's typeSymbol should never be inspected directly. override def safeToString = pre.toString + targs.mkString("(with type arguments ", ",", ")"); override def memberType(sym: Symbol) = pre.memberType(sym) match { - case PolyType(tparams, restp) => restp.subst(tparams, targs) - case ErrorType => ErrorType + case PolyType(tparams, restp) => + restp.subst(tparams, targs) +/* I don't think this is needed, as existential types close only over value types + case ExistentialType(tparams, qtpe) => + existentialAbstraction(tparams, qtpe.memberType(sym)) +*/ + case ErrorType => + ErrorType } override def kind = "AntiPolyType" } @@ -2206,10 +2212,11 @@ A type's typeSymbol should never be inspected directly. * referenced by type `tpe1'. * If there are no remaining type parameters, simply returns result type `tpe'. */ - def existentialAbstraction(tparams: List[Symbol], tpe: Type): Type = - if (tparams.isEmpty) tpe + def existentialAbstraction(tparams: List[Symbol], tpe0: Type): Type = + if (tparams.isEmpty) tpe0 else { var occurCount = emptySymCount ++ (tparams map (_ -> 0)) + val tpe = deAlias(tpe0) for (t <- tpe) { t match { case TypeRef(_, sym, _) => @@ -2272,6 +2279,16 @@ A type's typeSymbol should never be inspected directly. } } + /** Remove any occurrences of type aliases from this type */ + object deAlias extends TypeMap { + def apply(tp: Type): Type = mapOver { + tp match { + case TypeRef(pre, sym, args) if sym.isAliasType => tp.normalize + case _ => tp + } + } + } + /** Remove any occurrence of type <singleton> from this type and its parents */ object dropSingletonType extends TypeMap { def apply(tp: Type): Type = { diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index fbd0ad6385..c9a43270a1 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -121,9 +121,11 @@ abstract class Constructors extends Transform { // Create an assignment to class field `to' with rhs `from' def mkAssign(to: Symbol, from: Tree): Tree = localTyper.typed { - atPos(to.pos) { - Assign(Select(This(clazz), to), from) - } + //util.trace("compiling "+unit+" ") { + atPos(to.pos) { + Assign(Select(This(clazz), to), from) + } + //} } // Create code to copy parameter to parameter accessor field. diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 6c7a126ccc..9bc6968e02 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -287,7 +287,7 @@ self: Analyzer => */ val wildPt = approximate(pt) - if (traceImplicits) println("typed impl for "+wildPt+"? "+info.name+":"+info.tpe+"/"+undetParams) + //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)) { @@ -296,7 +296,7 @@ self: Analyzer => 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 "+wildPt) def fail(reason: String): SearchResult = { if (settings.XlogImplicits.value) inform(itree+" is not a valid implicit value for "+pt0+" because:\n"+reason) @@ -488,33 +488,76 @@ self: Analyzer => List() } + /** The parts of a type is the smallest set of types that contains + * - the type itself + * - the parts of its immediate components (prefix and argument) + * - the parts of its base types + */ + private def parts(tp: Type): List[Type] = { + val partMap = new collection.jcl.LinkedHashMap[Symbol, List[Type]] + /** Add a new type to partMap, unless a subtype of it with the same + * type symbol exists already. + */ + def addType(newtp: Type): Boolean = { + val tsym = newtp.typeSymbol + partMap.get(tsym) match { + case Some(ts) => + if (ts exists (_ <:< newtp)) false + else { partMap.put(tsym, newtp :: ts); true } + case None => + partMap.put(tsym, List(newtp)); true + } + } + /** Enter all parts of `tp` into `partMap` + */ + def getParts(tp: Type) { + tp match { + case TypeRef(pre, sym, args) if (!sym.isPackageClass) => + if (sym.isClass && !sym.isRefinementClass && !sym.isAnonymousClass) { + if (addType(tp)) { + for (bc <- sym.info.baseClasses.tail) + getParts(tp.baseType(bc)) + getParts(pre) + args foreach getParts + } + } else if (sym.isAliasType) { + getParts(tp.normalize) + } else if (sym.isAbstractType) { + getParts(tp.bounds.hi) + } + case ThisType(_) => + getParts(tp.widen) + case _: SingletonType => + getParts(tp.widen) + case RefinedType(ps, _) => + for (p <- ps) getParts(p) + case AnnotatedType(_, t, _) => + getParts(t) + case ExistentialType(tparams, t) => + getParts(t) + case _ => + } + } + /** Gives a list of typerefs with the same type symbol, + * remove all those that have a prefix which is a supertype + * of some other elements's prefix. + */ + def compactify(ts: List[Type]): List[Type] = ts match { + case List() => ts + case (t @ TypeRef(pre, _, _)) :: ts1 => + if (ts1 exists (_.prefix <:< pre)) compactify(ts1) + else t :: compactify(ts1 remove (pre <:< _.prefix)) + } + getParts(tp) + for ((k, ts) <- partMap.elements.toList; t <- compactify(ts)) yield t + } + /** The implicits made available by type `pt`. * These are all implicits found in companion objects of classes C * such that some part of `tp` has C as one of its superclasses. */ - private def implicitsOfExpectedType: List[List[ImplicitInfo]] = { - def getParts(tp: Type, s: collection.jcl.Set[Type]) { - tp match { - case TypeRef(pre, sym, args) if (!sym.isPackageClass) => - for (bc <- sym.info.baseClasses) - if (sym.isClass) s add (tp.baseType(bc)) - getParts(pre, s) - for (arg <- args) getParts(arg, s) - case ThisType(_) => - getParts(tp.widen, s) - case _: SingletonType => - getParts(tp.widen, s) - case RefinedType(ps, _) => - for (p <- ps) getParts(p, s) - case AnnotatedType(_, t, _) => - getParts(t, s) - case _ => - } - } - val tps = new collection.jcl.LinkedHashSet[Type] - getParts(pt, tps) - tps.elements.map(implicitsOfClass).toList - } + private def implicitsOfExpectedType: List[List[ImplicitInfo]] = + parts(pt).elements.map(implicitsOfClass).toList /** The manifest corresponding to type `pt`, provided `pt` is an instance of Manifest. */ @@ -598,6 +641,8 @@ self: Analyzer => val resultTree = implicitManifest(pt) if (resultTree != EmptyTree) result = new SearchResult(resultTree, EmptyTreeTypeSubstituter) } + if (result == SearchFailure && settings.verbose.value) //!!! + println("no implicits found for "+pt+" "+pt.typeSymbol.info.baseClasses+" "+parts(pt)+implicitsOfExpectedType) if (util.Statistics.enabled) impltime += (currentTime - startTime) result } diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 3e267fcda2..fb018647ff 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -463,6 +463,7 @@ trait Infer { case _ => restpe } + //println("try to solve "+tvars+" "+tparams) solvedTypes(tvars, tparams, tparams map varianceInType(varianceType), false, lubDepth(List(restpe, pt))) } catch { diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index dec6d58b45..35442e10e7 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -571,10 +571,12 @@ trait Typers { self: Analyzer => case SelectFromTypeTree(qual, _) => Select(qual, nme.PACKAGEkw) } } - val tree1 = tree match { - case Ident(name) => Select(qual, name) - case Select(_, name) => Select(qual, name) - case SelectFromTypeTree(_, name) => SelectFromTypeTree(qual, name) + val tree1 = atPos(tree.pos) { + tree match { + case Ident(name) => Select(qual, name) + case Select(_, name) => Select(qual, name) + case SelectFromTypeTree(_, name) => SelectFromTypeTree(qual, name) + } } val tree2 = checkAccessible(tree1, sym, qual.tpe, qual) tree2 @@ -745,7 +747,7 @@ trait Typers { self: Analyzer => context.undetparams = context.undetparams ::: tparams1 adapt(tree1 setType restpe.substSym(tparams, tparams1), mode, pt) case mt: ImplicitMethodType if ((mode & (EXPRmode | FUNmode | LHSmode)) == EXPRmode) => // (4.1) - if (!context.undetparams.isEmpty && (mode & POLYmode) == 0) { // (9) + if (!context.undetparams.isEmpty/* && (mode & POLYmode) == 0 disabled to make implicits in new collection work; we should revisit this. */) { // (9) context.undetparams = inferExprInstance( tree, context.extractUndetparams(), pt, mt.paramTypes exists isManifest) // if we are looking for a manifest, instantiate type to Nothing anyway, @@ -1479,12 +1481,13 @@ trait Typers { self: Analyzer => val typedMods = typedModifiers(tdef.mods) val rhs1 = checkNoEscaping.privates(tdef.symbol, typedType(tdef.rhs)) checkNonCyclic(tdef.symbol) - rhs1.tpe match { - case TypeBounds(lo1, hi1) => - if (!(lo1 <:< hi1)) - error(tdef.pos, "lower bound "+lo1+" does not conform to upper bound "+hi1) - case _ => - } + if (tdef.symbol.owner.isType) + rhs1.tpe match { + case TypeBounds(lo1, hi1) => + if (!(lo1 <:< hi1)) + error(tdef.pos, "lower bound "+lo1+" does not conform to upper bound "+hi1) + case _ => + } copy.TypeDef(tdef, typedMods, tdef.name, tparams1, rhs1) setType NoType } @@ -2516,7 +2519,7 @@ trait Typers { self: Analyzer => copy.Assign(tree, lhs1, checkDead(rhs1)) setType UnitClass.tpe } else { if (!lhs1.tpe.isError) { - //println(lhs1+" = "+rhs)//DEBUG + //println(lhs1+" = "+rhs+" "+varsym+" "+mayBeVarGetter(varsym)+" "+varsym.ownerChain+" "+varsym.info)// DEBUG error(tree.pos, if ((varsym ne null) && varsym.isValue) "reassignment to val" else "assignment to non variable") @@ -3064,7 +3067,7 @@ trait Typers { self: Analyzer => if (defSym.exists && impSym.exists) { // imported symbols take precedence over package-owned symbols in different // compilation units. Defined symbols take precedence over errenous imports. - if (defSym.owner.isPackageClass && + if (defSym.definedInPackage && ((!inIDE && !currentRun.compiles(defSym)) || (context.unit ne null) && defSym.sourceFile != context.unit.source.file)) defSym = NoSymbol diff --git a/test/files/neg/bug608.check b/test/files/neg/bug608.check index 8337c513ff..4e8eb4d709 100644 --- a/test/files/neg/bug608.check +++ b/test/files/neg/bug608.check @@ -1,6 +1,6 @@ bug608.scala:16: error: type mismatch; found : (a) => a - required: (_1.a) => ? where val _1: hs{type s = hs; type a = ha} + required: (ha) => ? = g(f(x).bimap(id)) ^ one error found diff --git a/test/files/run/constrained-types.check b/test/files/run/constrained-types.check index d3c32b7a02..6ab12ad34c 100644 --- a/test/files/run/constrained-types.check +++ b/test/files/run/constrained-types.check @@ -69,11 +69,11 @@ four: java.lang.String = four ----- val four2 = m(four) // should have an existential bound -four2: String @Annot(x) forSome { val x: java.lang.String } = four +four2: java.lang.String @Annot(x) forSome { val x: java.lang.String } = four ----- val four3 = four2 // should have the same type as four2 -four3: String @Annot(x) forSome { val x: java.lang.String } = four +four3: java.lang.String @Annot(x) forSome { val x: java.lang.String } = four ----- val stuff = m("stuff") // should not crash @@ -93,7 +93,7 @@ def m = { val y : String @Annot(x) = x y } // x should be existentially bound -m: String @Annot(x) forSome { val x: java.lang.String } +m: java.lang.String @Annot(x) forSome { val x: java.lang.String } ----- def n(y: String) = { @@ -105,7 +105,7 @@ def n(y: String) = { } m("stuff".stripMargin) } // x should be existentially bound -n: (String)String @Annot(x) forSome { val x: String } +n: (String)java.lang.String @Annot(x) forSome { val x: String } ----- class rep extends Annotation |