summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntonio Cunei <antonio.cunei@epfl.ch>2010-09-01 17:55:07 +0000
committerAntonio Cunei <antonio.cunei@epfl.ch>2010-09-01 17:55:07 +0000
commit512a7a03e0c0a964f067483930f430b05eae744d (patch)
treea0b3527934ed1f5ae1f051573541419f85595dcd
parent7f1e23872efb20a1cebe765ee319e628582dd517 (diff)
downloadscala-512a7a03e0c0a964f067483930f430b05eae744d.tar.gz
scala-512a7a03e0c0a964f067483930f430b05eae744d.tar.bz2
scala-512a7a03e0c0a964f067483930f430b05eae744d.zip
Merged revisions 22508-22520,22523,22545,22710,...
Merged revisions 22508-22520,22523,22545,22710,22726-22727,22754-22755,22762,22796,22804- 22805 via svnmerge from https://lampsvn.epfl.ch/svn-repos/scala/scala/trunk ........ r22508 | moors | 2010-07-08 17:58:41 +0200 (Thu, 08 Jul 2010) | 7 lines closes #2331: the pre-transform in Erasure did not correctly recurse in the case of a TypeApply. It simply returned the function, which might very well have been, say, a Select node, which had to be erased in case the qualifier's type is a refinement. (sorry about the whitespace changes) review by odersky ........ r22509 | moors | 2010-07-08 17:58:47 +0200 (Thu, 08 Jul 2010) | 7 lines closes #2416. this is a big one... typedAppliedTypeTree performed type application (beta-reduction) without checking whether that application was well-kinded this patch introduces a new subclass of TypeTree: TypeTreeWithDeferredRefCheck, which tracks the type args and type params of a type application when it was beta-reduced during typing without checking that the application was well-kinded -- that check must wait until refchecks, but was never performed since the application had been beta-reduced away caveat discovered while working on the fix: adapt turned all trees for which _.isType holds into TypeTree's review by odersky ........ r22510 | moors | 2010-07-08 17:58:52 +0200 (Thu, 08 Jul 2010) | 2 lines closes #3247: syntax error regarding context bounds generalized to include view bounds as we cannot easily be more specific no review ........ r22511 | moors | 2010-07-08 17:58:56 +0200 (Thu, 08 Jul 2010) | 2 lines closes #3249. exclude method type parameters from java generic signature of a class review by dragos ........ r22512 | moors | 2010-07-08 17:59:00 +0200 (Thu, 08 Jul 2010) | 2 lines closes #3374. checkKindBoundsHK did not instantiate hk params far enough. see also neg/bug1275 review by odersky ........ r22513 | moors | 2010-07-08 17:59:05 +0200 (Thu, 08 Jul 2010) | 5 lines closes #3399. mergePrefixAndArgs expects types that have equal type symbols (modulo normalization) but did not normalize these types before retrieving their typeArgs this broke the invariant that argss is a regular matrix review by odersky ........ r22514 | moors | 2010-07-08 17:59:10 +0200 (Thu, 08 Jul 2010) | 15 lines closes #3477. type arguments that were inferred to be Nothing should be included in checkBounds. wonder why they weren't in the first place note that all type parameters must be reported in error messages about failing type inference, but only type parameters that were inferred successfully should be substituted the idea of mapping type parameter symbols to the corresponding type ref in order to make substitution the identity does not seem to work, leading to errors like: src/library/scala/collection/immutable/SortedMap.scala:38: error: type mismatch; found : scala.collection.immutable.SortedMap[A,B(in method empty)] required: scala.collection.immutable.SortedMap[A,B(in trait SortedMap)] override def empty: SortedMap[A, B] = SortedMap.empty ^ (I guess that's why they were retracted before, but that wasn't done consistently, leading to #3152 -- my first attempt at fixing the latter lead to this bug... I've assigned #3152 to you Martin, as I can't decide how to fix it.) review by odersky ........ r22515 | moors | 2010-07-08 17:59:15 +0200 (Thu, 08 Jul 2010) | 5 lines closes #3486. members of implclasses are clones of the original trait members, but cloning discards a symbol's typehistory so that javaSig could not look at the symbol's type before erasure fixed by having mixin do the cloning at the beginning of erasure and then updating the symbol's info to transform it to be valid in current phase review by odersky ........ r22516 | moors | 2010-07-08 17:59:19 +0200 (Thu, 08 Jul 2010) | 3 lines closes #3494. don't let type argument for inserted wrapRefArray be inferred (as the expected element type of the array could be a singleton type, but that won't be inferred) review by prokopec ........ r22517 | moors | 2010-07-08 17:59:23 +0200 (Thu, 08 Jul 2010) | 1 line closes #3507: don't generate manifests where we can't refer to the existentially bound value ........ r22518 | moors | 2010-07-08 17:59:27 +0200 (Thu, 08 Jul 2010) | 3 lines closes #742. be more resilient to evil, ill-kinded type applications, so we don't crash (subst assumes from.length == to.length), and get to actually telling off the user for writing those nasty, nasty types review by extempore ........ r22519 | moors | 2010-07-08 17:59:32 +0200 (Thu, 08 Jul 2010) | 2 lines closes #3622: refchecks erased types without uncurrying them first review by odersky ........ r22520 | moors | 2010-07-08 17:59:36 +0200 (Thu, 08 Jul 2010) | 1 line made typechecker logging methods final so they can actually be inlined ........ r22523 | moors | 2010-07-09 02:24:02 +0200 (Fri, 09 Jul 2010) | 3 lines cleaned up the mess that resulted from cobbling together fixes for see #3477 and see #3152 adjustTypeArgs and methTypeArgs now return a LinkedHashMap[Symbol, Option[Type]] TODO: check that type inference is still just as lightning fast as before ........ r22545 | moors | 2010-07-12 19:03:03 +0200 (Mon, 12 Jul 2010) | 7 lines Closes #3653. In uncurry phase, remove IMPLICIT flag from implicit parameter list. no review Author: Mark Harrah <dmharrah@gmail.com> Date: Thu Jul 8 10:30:57 2010 -0400 Source: http://github.com/harrah/scala-starrless/commit/0c7759c95b47cebc6d9fa77cefd34ef638e2706e Reviewer: moors ........ r22710 | moors | 2010-08-09 13:51:37 +0200 (Mon, 09 Aug 2010) | 10 lines closes #3582: typedTypeDef needs to run in a new typer for TypeDefs with type parameters this was honored when typedTypeDef was called by typed1, but other callers did not this would cause higher-order type parameters to be re-entered in the scope of a method or a class (by the way, should we recycle scopes for higher-order type params? now new scopes are created, symbols entered, and tree's symbols updated) changed some spurious vars to vals review by odersky ........ r22726 | moors | 2010-08-10 23:06:00 +0200 (Tue, 10 Aug 2010) | 5 lines closes #3676: cycle detection logic in BaseTypeSeq's should not overwrite elements in the BTS for cycle detection as these markers may be witnessed by callbacks in mergePrefixAndArgs now using a mutable bitset to keep track of which computations are pending -- benchmarked for speed, memory consumption not checked review by odersky ........ r22727 | moors | 2010-08-10 23:12:13 +0200 (Tue, 10 Aug 2010) | 5 lines different approach to manifests of type parameters: before, ambiguity was prevented by leaving type inference failures (Nothing was inferred) in the expression that needs an implicit manifest -- we now put these back in undetparams (maybe they will be inferred) and when we need to produce a manifest for an undetermined parameter (it ended up not being inferred), we assume it will get instantiated to Nothing (but for now don't actually reflect that in the SearchResult, as instantiate should take care of that anyway) see test file for use case that works with this new scheme, but did not work before: the eager instantiation of type params to Nothing before implicit search even got started would indeed prevent ambiguity -- unfortunately it also ruled out valid code like this (where the type parameter is inferred successfully by the time the manifest is needed) review by odersky ........ r22754 | moors | 2010-08-13 18:21:40 +0200 (Fri, 13 Aug 2010) | 10 lines closes #3419: test files omit check that wouldn't work with separate compilation, not needed anymore because compiler has become more robust the actual fix was committed as part of r22512, see #3374 also see #3512 no review ........ r22755 | moors | 2010-08-13 18:21:44 +0200 (Fri, 13 Aug 2010) | 8 lines closes #3663. disregard package nesting for access check of java syms namers wasn't setting privateWithin on java-defined variables (btw, ) shouldn't clone carry over privateWithin? better treatment of linked ) class access boundary (only check for access within linked class if ) it actually exists ) would have liked more control for the test case: only javac should compile the java file, then scalac should compile the scala file and fail review by odersky ........ r22762 | moors | 2010-08-14 10:19:56 +0200 (Sat, 14 Aug 2010) | 5 lines closes #3691. moved kind conformance checks to types because it needs to be checked as part of specializesSym. TODO: clean this up, introduce datatypes to denote kinds, split checkKindBounds into kind inference and subkind checking review by odersky ........ r22796 | moors | 2010-08-19 14:20:28 +0200 (Thu, 19 Aug 2010) | 3 lines closes #3777. type constructor inference now tries harder to unify a type constructor variable (that's applied to type arguments) with a type alias by dealiasing it, hoping to discover a concrete type constructor (that's applied to type arguments). no review ........ r22804 | moors | 2010-08-20 16:48:12 +0200 (Fri, 20 Aug 2010) | 12 lines closes 2462. better implicit error messages. @implicitNotFound(msg="Custom error message that may refer to type parameters ${T} and ${U}") trait Constraint[T, U] whenever an implicit argument of type Constraint[A, B] cannot be found, the custom error message will be used, where the type arguments are interpolated in the obvious way note: if the msg in the annotation references non-existing type params, a warning is emitted the patch also cleans up annotation argument retrieval (moved it to AnnotationInfo from Symbol) review by odersky ........ r22805 | moors | 2010-08-21 10:25:00 +0200 (Sat, 21 Aug 2010) | 1 line forgot to update check file after renaming tests. no review. ........
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreePrinters.scala4
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala15
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala4
-rw-r--r--src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala12
-rw-r--r--src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala76
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala1
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala22
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala219
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala289
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala19
-rw-r--r--src/compiler/scala/tools/nsc/transform/TypingTransformers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala48
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala68
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala201
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala39
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala44
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala123
-rw-r--r--src/library/scala/annotation/implicitNotFound.scala18
-rw-r--r--src/library/scala/collection/generic/CanBuildFrom.scala3
-rw-r--r--test/files/neg/bug1275.check8
-rw-r--r--test/files/neg/bug1275.scala29
-rw-r--r--test/files/neg/bug882.check2
-rw-r--r--test/files/neg/t2416.check10
-rw-r--r--test/files/neg/t2416.scala14
-rw-r--r--test/files/neg/t2462a.check4
-rw-r--r--test/files/neg/t2462a.scala3
-rw-r--r--test/files/neg/t2462b.check14
-rw-r--r--test/files/neg/t2462b.scala12
-rw-r--r--test/files/neg/t3399.check4
-rw-r--r--test/files/neg/t3399.scala24
-rw-r--r--test/files/neg/t3507.check4
-rw-r--r--test/files/neg/t3507.scala15
-rw-r--r--test/files/neg/t3653.check7
-rw-r--r--test/files/neg/t3653.scala4
-rw-r--r--test/files/neg/t3663.check4
-rw-r--r--test/files/neg/t3663/PackageProtected.java5
-rw-r--r--test/files/neg/t3663/main.scala14
-rw-r--r--test/files/neg/t3691.check16
-rw-r--r--test/files/neg/t3691.scala11
-rw-r--r--test/files/neg/t742.check5
-rw-r--r--test/files/neg/t742.scala8
-rw-r--r--test/files/pos/nothing_manifest_disambig.scala10
-rw-r--r--test/files/pos/t2331.scala11
-rw-r--r--test/files/pos/t3249/Test.java5
-rw-r--r--test/files/pos/t3249/a.scala11
-rw-r--r--test/files/pos/t3374.scala6
-rw-r--r--test/files/pos/t3419/B_1.scala3
-rw-r--r--test/files/pos/t3419/C_2.scala3
-rw-r--r--test/files/pos/t3477.scala7
-rw-r--r--test/files/pos/t3486/JTest.java3
-rw-r--r--test/files/pos/t3486/test.scala6
-rw-r--r--test/files/pos/t3494.scala7
-rw-r--r--test/files/pos/t3582.scala12
-rw-r--r--test/files/pos/t3582b.scala5
-rw-r--r--test/files/pos/t3622/test/AsyncTask.java5
-rw-r--r--test/files/pos/t3622/test/MyAsyncTask.java9
-rw-r--r--test/files/pos/t3622/test/Test.scala5
-rw-r--r--test/files/pos/t3676.scala5
-rw-r--r--test/files/pos/t3777.scala7
61 files changed, 1042 insertions, 508 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index 5044105684..41e93ae386 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -137,7 +137,7 @@ abstract class TreeGen {
assert(!tree.tpe.isInstanceOf[MethodType], tree)
assert(!pt.typeSymbol.isPackageClass)
assert(!pt.typeSymbol.isPackageObjectClass)
- assert(pt eq pt.normalize) //@MAT only called during erasure, which already takes care of that
+ assert(pt eq pt.normalize, tree +" : "+ debugString(pt) +" ~>"+ debugString(pt.normalize)) //@MAT only called during erasure, which already takes care of that
atPos(tree.pos)(mkAsInstanceOf(tree, pt, false))
}
diff --git a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala
index ddc1c3169a..e1e7c90879 100644
--- a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala
@@ -379,6 +379,9 @@ trait TreePrinters { trees: SymbolTable =>
case SelectFromArray(qualifier, name, _) =>
print(qualifier); print(".<arr>"); print(symName(tree, name))
+ case TypeTreeWithDeferredRefCheck() =>
+ print("<tree with deferred refcheck>")
+
case tree =>
print("<unknown tree of class "+tree.getClass+">")
}
@@ -575,6 +578,7 @@ trait TreePrinters { trees: SymbolTable =>
// eliminated by refchecks
case ModuleDef(mods, name, impl) =>
+ case TypeTreeWithDeferredRefCheck() =>
// eliminated by erasure
case TypeDef(mods, name, tparams, rhs) =>
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index 35db3c0984..dbe4a587ba 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -338,6 +338,9 @@ trait Trees extends reflect.generic.Trees { self: SymbolTable =>
case class Parens(args: List[Tree]) extends Tree // only used during parsing
+ /** emitted by typer, eliminated by refchecks **/
+ case class TypeTreeWithDeferredRefCheck()(val check: () => TypeTree) extends AbsTypeTree
+
// ----- subconstructors --------------------------------------------
class ApplyToImplicitArgs(fun: Tree, args: List[Tree]) extends Apply(fun, args)
@@ -383,6 +386,7 @@ trait Trees extends reflect.generic.Trees { self: SymbolTable =>
def Ident(tree: Tree, name: Name): Ident
def Literal(tree: Tree, value: Constant): Literal
def TypeTree(tree: Tree): TypeTree
+ def TypeTreeWithDeferredRefCheck(tree: Tree): TypeTreeWithDeferredRefCheck
def Annotated(tree: Tree, annot: Tree, arg: Tree): Annotated
def SingletonTypeTree(tree: Tree, ref: Tree): SingletonTypeTree
def SelectFromTypeTree(tree: Tree, qualifier: Tree, selector: Name): SelectFromTypeTree
@@ -470,6 +474,9 @@ trait Trees extends reflect.generic.Trees { self: SymbolTable =>
new Literal(value).copyAttrs(tree)
def TypeTree(tree: Tree) =
new TypeTree().copyAttrs(tree)
+ def TypeTreeWithDeferredRefCheck(tree: Tree) = tree match {
+ case dc@TypeTreeWithDeferredRefCheck() => new TypeTreeWithDeferredRefCheck()(dc.check).copyAttrs(tree)
+ }
def Annotated(tree: Tree, annot: Tree, arg: Tree) =
new Annotated(annot, arg).copyAttrs(tree)
def SingletonTypeTree(tree: Tree, ref: Tree) =
@@ -670,6 +677,10 @@ trait Trees extends reflect.generic.Trees { self: SymbolTable =>
case t @ TypeTree() => t
case _ => treeCopy.TypeTree(tree)
}
+ def TypeTreeWithDeferredRefCheck(tree: Tree) = tree match {
+ case t @ TypeTreeWithDeferredRefCheck() => t
+ case _ => treeCopy.TypeTreeWithDeferredRefCheck(tree)
+ }
def Annotated(tree: Tree, annot: Tree, arg: Tree) = tree match {
case t @ Annotated(annot0, arg0)
if (annot0==annot) => t
@@ -816,6 +827,8 @@ trait Trees extends reflect.generic.Trees { self: SymbolTable =>
treeCopy.Literal(tree, value)
case TypeTree() =>
treeCopy.TypeTree(tree)
+ case TypeTreeWithDeferredRefCheck() =>
+ treeCopy.TypeTreeWithDeferredRefCheck(tree)
case Annotated(annot, arg) =>
treeCopy.Annotated(tree, transform(annot), transform(arg))
case SingletonTypeTree(ref) =>
@@ -878,6 +891,8 @@ trait Trees extends reflect.generic.Trees { self: SymbolTable =>
traverse(definition)
case Parens(ts) =>
traverseTrees(ts)
+ case TypeTreeWithDeferredRefCheck() => // TODO: should we traverse the wrapped tree?
+ // (and rewrap the result? how to update the deferred check? would need to store wrapped tree instead of returning it from check)
case _ => super.traverse(tree)
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index e28f07e840..f3149f7723 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -1820,7 +1820,7 @@ self =>
if (in.token != RPAREN) {
if (in.token == IMPLICIT) {
if (!contextBounds.isEmpty)
- syntaxError("cannot have both implicit parameters and context bounds `: ...' on type parameters", false)
+ syntaxError("cannot have both implicit parameters and context bounds `: ...' or view bounds `<% ...' on type parameters", false)
in.nextToken()
implicitmod = Flags.IMPLICIT
}
@@ -2328,7 +2328,7 @@ self =>
classContextBounds = contextBoundBuf.toList
val tstart = (in.offset::classContextBounds.map(_.pos.startOrPoint)).min
if (!classContextBounds.isEmpty && mods.hasFlag(Flags.TRAIT)) {
- syntaxError("traits cannot have type parameters with context bounds `: ...'", false)
+ syntaxError("traits cannot have type parameters with context bounds `: ...' nor view bounds `<% ...'", false)
classContextBounds = List()
}
val constrAnnots = annotations(false, true)
diff --git a/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala b/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala
index 40177fad10..2429f53aa1 100644
--- a/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala
+++ b/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala
@@ -123,6 +123,18 @@ trait AnnotationInfos extends reflect.generic.AnnotationInfos { self: SymbolTabl
val subs = new TreeSymSubstituter(List(from), List(to))
AnnotationInfo(atp, args.map(subs(_)), assocs).setPos(pos)
}
+
+ // !!! when annotation arguments are not literal strings, but any sort of
+ // assembly of strings, there is a fair chance they will turn up here not as
+ // Literal(const) but some arbitrary AST.
+ def stringArg(index: Int): Option[String] = if(args.size > index) Some(args(index) match {
+ case Literal(const) => const.stringValue
+ case x => x.toString // should not be necessary, but better than silently ignoring an issue
+ }) else None
+
+ def intArg(index: Int): Option[Int] = if(args.size > index) Some(args(index)) collect {
+ case Literal(Constant(x: Int)) => x
+ } else None
}
object AnnotationInfo extends AnnotationInfoExtractor
diff --git a/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala b/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala
index c83138e9bc..c230533765 100644
--- a/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala
+++ b/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala
@@ -6,8 +6,7 @@ package scala.tools.nsc
package symtab
// todo implement in terms of BitSet
-import scala.collection.mutable.ListBuffer
-import scala.collection.immutable.Map
+import scala.collection.mutable.{ListBuffer, BitSet}
import math.max
import util.Statistics._
@@ -32,45 +31,48 @@ trait BaseTypeSeqs {
class BaseTypeSeq(parents: List[Type], elems: Array[Type]) {
self =>
-
incCounter(baseTypeSeqCount)
incCounter(baseTypeSeqLenTotal, elems.length)
/** The number of types in the sequence */
def length: Int = elems.length
- var pending: Map[Int, Type] = Map()
+ // #3676 shows why we can't store NoType in elems to mark cycles
+ // (while NoType is in there to indicate a cycle in this BTS, during the execution of
+ // the mergePrefixAndArgs below, the elems get copied without the pending map,
+ // so that NoType's are seen instead of the original type --> spurious compile error)
+ val pending = new BitSet(length)
/** The type at i'th position in this sequence; lazy types are returned evaluated. */
- def apply(i: Int): Type = elems(i) match {
- case NoType =>
- pending = Map()
- elems(i) = AnyClass.tpe
+ def apply(i: Int): Type =
+ if(pending contains i) {
+ pending.clear()
throw CyclicInheritance
- case rtp @ RefinedType(variants, decls) =>
- // can't assert decls.isEmpty; see t0764
- //if (!decls.isEmpty) assert(false, "computing closure of "+this+":"+this.isInstanceOf[RefinedType]+"/"+closureCache(j))
- //Console.println("compute closure of "+this+" => glb("+variants+")")
- pending += (i -> rtp)
- elems(i) = NoType
- try {
- mergePrefixAndArgs(variants, -1, lubDepth(variants)) match {
- case Some(tp0) =>
- pending -= i
- elems(i) = tp0
- tp0
- case None =>
- typeError(
- "no common type instance of base types "+(variants mkString ", and ")+" exists.")
- }
- } catch {
- case CyclicInheritance =>
- typeError(
- "computing the common type instance of base types "+(variants mkString ", and ")+" leads to a cycle.")
+ } else
+ elems(i) match {
+ case rtp @ RefinedType(variants, decls) =>
+ // can't assert decls.isEmpty; see t0764
+ //if (!decls.isEmpty) assert(false, "computing closure of "+this+":"+this.isInstanceOf[RefinedType]+"/"+closureCache(j))
+ //Console.println("compute closure of "+this+" => glb("+variants+")")
+ pending += i
+ try {
+ mergePrefixAndArgs(variants, -1, lubDepth(variants)) match {
+ case Some(tp0) =>
+ pending(i) = false
+ elems(i) = tp0
+ tp0
+ case None =>
+ typeError(
+ "no common type instance of base types "+(variants mkString ", and ")+" exists.")
+ }
+ } catch {
+ case CyclicInheritance =>
+ typeError(
+ "computing the common type instance of base types "+(variants mkString ", and ")+" leads to a cycle.")
+ }
+ case tp =>
+ tp
}
- case tp =>
- tp
- }
def rawElem(i: Int) = elems(i)
@@ -78,17 +80,9 @@ trait BaseTypeSeqs {
* no evaluation needed.
*/
def typeSymbol(i: Int): Symbol = {
- def tsym(tp: Type) = tp match {
- case RefinedType(v :: vs, _) => v.typeSymbol
- case _ => tp.typeSymbol
- }
elems(i) match {
- case NoType =>
- pending get i match {
- case Some(tp) => tsym(tp)
- case _ => NoType.typeSymbol
- }
- case tp => tsym(tp)
+ case RefinedType(v :: vs, _) => v.typeSymbol
+ case tp => tp.typeSymbol
}
}
diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
index 3e3b32ac01..92d8b213c1 100644
--- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
@@ -120,6 +120,7 @@ trait Definitions extends reflect.generic.StandardDefinitions {
lazy val TailrecClass = getClass("scala.annotation.tailrec")
lazy val SwitchClass = getClass("scala.annotation.switch")
lazy val ElidableMethodClass = getClass("scala.annotation.elidable")
+ lazy val ImplicitNotFoundClass = getClass("scala.annotation.implicitNotFound")
lazy val FieldTargetClass = getClass("scala.annotation.target.field")
lazy val GetterTargetClass = getClass("scala.annotation.target.getter")
lazy val SetterTargetClass = getClass("scala.annotation.target.setter")
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index 10a7bbf705..e16612ae49 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -132,14 +132,6 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
def getAnnotation(cls: Symbol): Option[AnnotationInfo] =
annotations find (_.atp.typeSymbol == cls)
- /** Finds the requested annotation and returns Some(Tree) containing
- * the argument at position 'index', or None if either the annotation
- * or the index does not exist.
- */
- private def getAnnotationArg(cls: Symbol, index: Int) =
- for (AnnotationInfo(_, args, _) <- getAnnotation(cls) ; if args.size > index) yield
- args(index)
-
/** Remove all annotations matching the given class. */
def removeAnnotation(cls: Symbol): Unit =
setAnnotations(annotations filterNot (_.atp.typeSymbol == cls))
@@ -461,18 +453,16 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
}
def isDeprecated = hasAnnotation(DeprecatedAttr)
- def deprecationMessage = getAnnotationArg(DeprecatedAttr, 0) collect { case Literal(const) => const.stringValue }
+ def deprecationMessage = getAnnotation(DeprecatedAttr) flatMap { _.stringArg(0) }
// !!! when annotation arguments are not literal strings, but any sort of
// assembly of strings, there is a fair chance they will turn up here not as
// Literal(const) but some arbitrary AST. However nothing in the compiler
// prevents someone from writing a @migration annotation with a calculated
// string. So this needs attention. For now the fact that migration is
// private[scala] ought to provide enough protection.
- def migrationMessage = getAnnotationArg(MigrationAnnotationClass, 2) collect {
- case Literal(const) => const.stringValue
- case x => x.toString // should not be necessary, but better than silently ignoring an issue
- }
- def elisionLevel = getAnnotationArg(ElidableMethodClass, 0) collect { case Literal(Constant(x: Int)) => x }
+ def migrationMessage = getAnnotation(MigrationAnnotationClass) flatMap { _.stringArg(2) }
+ def elisionLevel = getAnnotation(ElidableMethodClass) flatMap { _.intArg(0) }
+ def implicitNotFoundMsg = getAnnotation(ImplicitNotFoundClass) flatMap { _.stringArg(0) }
/** Does this symbol denote a wrapper object of the interpreter or its class? */
final def isInterpreterWrapper =
@@ -776,6 +766,7 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
assert(phaseId(infos.validFrom) <= phase.id)
if (phaseId(infos.validFrom) == phase.id) infos = infos.prev
infos = TypeHistory(currentPeriod, info, infos)
+ validTo = if (info.isComplete) currentPeriod else NoPeriod
this
}
@@ -1073,6 +1064,7 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
/** A clone of this symbol, but with given owner */
final def cloneSymbol(owner: Symbol): Symbol = {
val newSym = cloneSymbolImpl(owner)
+ // newSym.privateWithin = privateWithin // ?
newSym.setInfo(info.cloneInfo(newSym))
.setFlag(this.rawflags).setAnnotations(this.annotations)
}
@@ -1967,7 +1959,7 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
newTypeName(rawname+"$trait") // (part of DEVIRTUALIZE)
} else if (phase.flatClasses && rawowner != NoSymbol && !rawowner.isPackageClass) {
if (flatname == nme.EMPTY) {
- assert(rawowner.isClass, "fatal: %s has owner %s, but a class owner is required".format(rawname, rawowner))
+ assert(rawowner.isClass, "fatal: %s has owner %s, but a class owner is required".format(rawname+idString, rawowner))
flatname = newTypeName(compactify(rawowner.name.toString() + "$" + rawname))
}
flatname
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index 2eca101aab..7aed4cd648 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -137,7 +137,7 @@ trait Types extends reflect.generic.Types { self: SymbolTable =>
* It makes use of the fact that these two operations depend only on the parents,
* not on the refinement.
*/
- var intersectionWitness = new WeakHashMap[List[Type], Type]
+ val intersectionWitness = new WeakHashMap[List[Type], Type]
private object gen extends {
val global : Types.this.type = Types.this
@@ -394,9 +394,10 @@ trait Types extends reflect.generic.Types { self: SymbolTable =>
/** Replace formal type parameter symbols with actual type arguments.
*
- * Amounts to substitution except for higher-kinded types. (See overridden method in TypeRef) -- @M (contact adriaan.moors at cs.kuleuven.be)
+ * Amounts to substitution except for higher-kinded types. (See overridden method in TypeRef) -- @M
*/
- def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]): Type = this.subst(formals, actuals)
+ def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]): Type =
+ if(formals.length == actuals.length) this.subst(formals, actuals) else ErrorType
/** If this type is an existential, turn all existentially bound variables to type skolems.
* @param owner The owner of the created type skolems
@@ -1327,7 +1328,7 @@ trait Types extends reflect.generic.Types { self: SymbolTable =>
* to take the intersection of their bounds
*/
override def normalize = {
- if (isHigherKinded)
+ if (isHigherKinded) {
PolyType(
typeParams,
RefinedType(
@@ -1337,6 +1338,7 @@ trait Types extends reflect.generic.Types { self: SymbolTable =>
},
decls,
typeSymbol))
+ }
else super.normalize
}
@@ -1705,8 +1707,9 @@ A type's typeSymbol should never be inspected directly.
if (substTps.length == typeParams.length)
typeRef(pre, sym, actuals)
- else // partial application (needed in infer when bunching type arguments from classes and methods together)
+ else if(formals.length == actuals.length) // partial application (needed in infer when bunching type arguments from classes and methods together)
typeRef(pre, sym, dummyArgs).subst(formals, actuals)
+ else ErrorType
}
else
super.instantiateTypeParams(formals, actuals)
@@ -1725,21 +1728,15 @@ A type's typeSymbol should never be inspected directly.
if (sym == clazz && !args.isEmpty) args.head else this
def normalize0: Type =
- if (sym.isAliasType) { // beta-reduce
- if (sym.info.typeParams.length == args.length || !isHigherKinded) {
- /* !isHigherKinded && sym.info.typeParams.length != args.length only happens when compiling e.g.,
- `val x: Class' with -Xgenerics, while `type Class = java.lang.Class' had already been compiled without -Xgenerics */
- val xform = transform(sym.info.resultType)
- assert(xform ne this, this)
- xform.normalize // cycles have been checked in typeRef
- } else { // should rarely happen, if at all
- PolyType(sym.info.typeParams, transform(sym.info.resultType).normalize) // eta-expand -- for regularity, go through sym.info for typeParams
- // @M TODO: should not use PolyType, as that's the type of a polymorphic value -- we really want a type *function*
- }
- } else if (isHigherKinded) {
+ if (isHigherKinded) {
// @M TODO: should not use PolyType, as that's the type of a polymorphic value -- we really want a type *function*
// @M: initialize (by sym.info call) needed (see test/files/pos/ticket0137.scala)
PolyType(sym.info.typeParams, typeRef(pre, sym, dummyArgs)) // must go through sym.info for typeParams
+ } else if (sym.isAliasType) { // beta-reduce
+ if(sym.info.typeParams.length == args.length) // don't do partial application
+ transform(sym.info.resultType).normalize // cycles have been checked in typeRef
+ else
+ ErrorType
} else if (sym.isRefinementClass) {
sym.info.normalize // @MO to AM: OK?
//@M I think this is okay, but changeset 12414 (which fixed #1241) re-introduced another bug (#2208)
@@ -2247,14 +2244,17 @@ A type's typeSymbol should never be inspected directly.
if(params.isEmpty) { // type var has kind *
addBound(tp)
true
- } else // higher-kinded type var with same arity as tp
- (typeArgs.length == tp.typeArgs.length) && {
- // register type constructor (the type without its type arguments) as bound
- addBound(tp.typeConstructor)
- // check subtyping of higher-order type vars
- // use variances as defined in the type parameter that we're trying to infer (the result is sanity-checked later)
- checkArgs(tp.typeArgs, typeArgs, params)
- }
+ } else { // higher-kinded type var with same arity as tp
+ def unifyHK(tp: Type) =
+ (typeArgs.length == tp.typeArgs.length) && {
+ // register type constructor (the type without its type arguments) as bound
+ addBound(tp.typeConstructor)
+ // check subtyping of higher-order type vars
+ // use variances as defined in the type parameter that we're trying to infer (the result is sanity-checked later)
+ checkArgs(tp.typeArgs, typeArgs, params)
+ }
+ unifyHK(tp) || unifyHK(tp.dealias)
+ }
}
}
@@ -4244,9 +4244,8 @@ A type's typeSymbol should never be inspected directly.
// this optimisation holds because inlining cloneSymbols in `val tpsFresh = cloneSymbols(tparams1)` gives:
// val tpsFresh = tparams1 map (_.cloneSymbol)
// for (tpFresh <- tpsFresh) tpFresh.setInfo(tpFresh.info.substSym(tparams1, tpsFresh))
- }
}
-
+ }
case (_, _) => false // @assume !tp1.isHigherKinded || !tp2.isHigherKinded
// --> thus, cannot be subtypes (Any/Nothing has already been checked)
}))
@@ -4482,7 +4481,12 @@ A type's typeSymbol should never be inspected directly.
val info2 = tp2.memberInfo(sym2).substThis(tp2.typeSymbol, tp1)
//System.out.println("specializes "+tp1+"."+sym1+":"+info1+sym1.locationString+" AND "+tp2+"."+sym2+":"+info2)//DEBUG
sym2.isTerm && (info1 <:< info2) /*&& (!sym2.isStable || sym1.isStable) */ ||
- sym2.isAbstractType && info2.bounds.containsType(tp1.memberType(sym1)) ||
+ sym2.isAbstractType && {
+ val memberTp1 = tp1.memberType(sym1)
+ // println("kinds conform? "+(memberTp1, tp1, sym2, kindsConform(List(sym2), List(memberTp1), tp2, sym2.owner)))
+ info2.bounds.containsType(memberTp1) &&
+ kindsConform(List(sym2), List(memberTp1), tp1, sym1.owner)
+ } ||
sym2.isAliasType && tp2.memberType(sym2).substThis(tp2.typeSymbol, tp1) =:= tp1.memberType(sym1) //@MAT ok
}
@@ -5086,37 +5090,41 @@ A type's typeSymbol should never be inspected directly.
case List(tp) =>
Some(tp)
case TypeRef(_, sym, _) :: rest =>
- val pres = tps map (_.prefix)
+ val pres = tps map (_.prefix) // prefix normalizes automatically
val pre = if (variance == 1) lub(pres, depth) else glb(pres, depth)
- val argss = tps map (_.typeArgs)
+ val argss = tps map (_.normalize.typeArgs) // symbol equality (of the tp in tps) was checked using typeSymbol, which normalizes, so should normalize before retrieving arguments
val capturedParams = new ListBuffer[Symbol]
- val args = (sym.typeParams, argss.transpose).zipped map {
- (tparam, as) =>
- if (depth == 0)
- if (tparam.variance == variance) AnyClass.tpe
- else if (tparam.variance == -variance) NothingClass.tpe
- else NoType
- else
- if (tparam.variance == variance) lub(as, decr(depth))
- else if (tparam.variance == -variance) glb(as, decr(depth))
- else {
- val l = lub(as, decr(depth))
- val g = glb(as, decr(depth))
- if (l <:< g) l
- else { // Martin: I removed this, because incomplete. Not sure there is a good way to fix it. For the moment we
- // just err on the conservative side, i.e. with a bound that is too high.
- // if(!(tparam.info.bounds contains tparam)){ //@M can't deal with f-bounds, see #2251
- val qvar = commonOwner(as) freshExistential "" setInfo TypeBounds(g, l)
- capturedParams += qvar
- qvar.tpe
- }
- }
- }
try {
+ val args = (sym.typeParams, argss.transpose).zipped map {
+ (tparam, as) =>
+ if (depth == 0)
+ if (tparam.variance == variance) AnyClass.tpe
+ else if (tparam.variance == -variance) NothingClass.tpe
+ else NoType
+ else
+ if (tparam.variance == variance) lub(as, decr(depth))
+ else if (tparam.variance == -variance) glb(as, decr(depth))
+ else {
+ val l = lub(as, decr(depth))
+ val g = glb(as, decr(depth))
+ if (l <:< g) l
+ else { // Martin: I removed this, because incomplete. Not sure there is a good way to fix it. For the moment we
+ // just err on the conservative side, i.e. with a bound that is too high.
+ // if(!(tparam.info.bounds contains tparam)){ //@M can't deal with f-bounds, see #2251
+ val qvar = commonOwner(as) freshExistential "" setInfo TypeBounds(g, l)
+ capturedParams += qvar
+ qvar.tpe
+ }
+ }
+ }
if (args contains NoType) None
else Some(existentialAbstraction(capturedParams.toList, typeRef(pre, sym, args)))
} catch {
case ex: MalformedType => None
+ case ex: IndexOutOfBoundsException => // transpose freaked out because of irregular argss
+ // catching just in case (shouldn't happen, but also doesn't cost us)
+ if (settings.debug.value) log("transposed irregular matrix!?"+ (tps, argss))
+ None
}
case SingleType(_, sym) :: rest =>
val pres = tps map (_.prefix)
@@ -5184,6 +5192,113 @@ A type's typeSymbol should never be inspected directly.
throw new NoCommonType(tps)
}
+
+// TODO: this desperately needs to be cleaned up
+// plan: split into kind inference and subkinding
+// every Type has a (cached) Kind
+ def kindsConform(tparams: List[Symbol], targs: List[Type], pre: Type, owner: Symbol): Boolean = checkKindBounds0(tparams, targs, pre, owner, false).isEmpty
+
+ /** Check well-kindedness of type application (assumes arities are already checked) -- @M
+ *
+ * This check is also performed when abstract type members become concrete (aka a "type alias") -- then tparams.length==1
+ * (checked one type member at a time -- in that case, prefix is the name of the type alias)
+ *
+ * Type application is just like value application: it's "contravariant" in the sense that
+ * the type parameters of the supplied type arguments must conform to the type parameters of
+ * the required type parameters:
+ * - their bounds must be less strict
+ * - variances must match (here, variances are absolute, the variance of a type parameter does not influence the variance of its higher-order parameters)
+ * - @M TODO: are these conditions correct,sufficient&necessary?
+ *
+ * e.g. class Iterable[t, m[+x <: t]] --> the application Iterable[Int, List] is okay, since
+ * List's type parameter is also covariant and its bounds are weaker than <: Int
+ */
+ def checkKindBounds0(tparams: List[Symbol], targs: List[Type], pre: Type, owner: Symbol, explainErrors: Boolean): List[(Type, Symbol, List[(Symbol, Symbol)], List[(Symbol, Symbol)], List[(Symbol, Symbol)])] = {
+ var error = false
+
+ def transform(tp: Type, clazz: Symbol): Type = tp.asSeenFrom(pre, clazz) // instantiate type params that come from outside the abstract type we're currently checking
+ def transformedBounds(p: Symbol, o: Symbol) = transform(p.info.instantiateTypeParams(tparams, targs).bounds, o)
+
+ /** Check whether <arg>sym1</arg>'s variance conforms to <arg>sym2</arg>'s variance
+ *
+ * If <arg>sym2</arg> is invariant, <arg>sym1</arg>'s variance is irrelevant. Otherwise they must be equal.
+ */
+ def variancesMatch(sym1: Symbol, sym2: Symbol): Boolean = (sym2.variance==0 || sym1.variance==sym2.variance)
+
+ // check that the type parameters <arg>hkargs</arg> to a higher-kinded type conform to the expected params <arg>hkparams</arg>
+ def checkKindBoundsHK(hkargs: List[Symbol], arg: Symbol, param: Symbol, paramowner: Symbol, underHKParams: List[Symbol], withHKArgs: List[Symbol]): (List[(Symbol, Symbol)], List[(Symbol, Symbol)], List[(Symbol, Symbol)]) = {
+ def bindHKParams(tp: Type) = tp.substSym(underHKParams, withHKArgs)
+ // @M sometimes hkargs != arg.typeParams, the symbol and the type may have very different type parameters
+ val hkparams = param.typeParams
+
+ if(settings.debug.value) {
+ println("checkKindBoundsHK expected: "+ param +" with params "+ hkparams +" by definition in "+ paramowner)
+ println("checkKindBoundsHK supplied: "+ arg +" with params "+ hkargs +" from "+ owner)
+ println("checkKindBoundsHK under params: "+ underHKParams +" with args "+ withHKArgs)
+ }
+
+ if(hkargs.length != hkparams.length) {
+ if(arg == AnyClass || arg == NothingClass) (Nil, Nil, Nil) // Any and Nothing are kind-overloaded
+ else {error = true; (List((arg, param)), Nil, Nil)} // shortcut: always set error, whether explainTypesOrNot
+ } else {
+ val _arityMismatches = if(explainErrors) new ListBuffer[(Symbol, Symbol)] else null
+ val _varianceMismatches = if(explainErrors) new ListBuffer[(Symbol, Symbol)] else null
+ val _stricterBounds = if(explainErrors)new ListBuffer[(Symbol, Symbol)] else null
+ def varianceMismatch(a: Symbol, p: Symbol) { if(explainErrors) _varianceMismatches += ((a, p)) else error = true}
+ def stricterBound(a: Symbol, p: Symbol) { if(explainErrors) _stricterBounds += ((a, p)) else error = true }
+ def arityMismatches(as: Iterable[(Symbol, Symbol)]) { if(explainErrors) _arityMismatches ++= as }
+ def varianceMismatches(as: Iterable[(Symbol, Symbol)]) { if(explainErrors) _varianceMismatches ++= as }
+ def stricterBounds(as: Iterable[(Symbol, Symbol)]) { if(explainErrors) _stricterBounds ++= as }
+
+ for ((hkarg, hkparam) <- hkargs zip hkparams) {
+ if (hkparam.typeParams.isEmpty) { // base-case: kind *
+ if (!variancesMatch(hkarg, hkparam))
+ varianceMismatch(hkarg, hkparam)
+
+ // instantiateTypeParams(tparams, targs) --> higher-order bounds may contain references to type arguments
+ // substSym(hkparams, hkargs) --> these types are going to be compared as types of kind *
+ // --> their arguments use different symbols, but are conceptually the same
+ // (could also replace the types by polytypes, but can't just strip the symbols, as ordering is lost then)
+ if (!(bindHKParams(transformedBounds(hkparam, paramowner)) <:< transform(hkarg.info.bounds, owner)))
+ stricterBound(hkarg, hkparam)
+
+ if(settings.debug.value) {
+ println("checkKindBoundsHK base case: "+ hkparam +" declared bounds: "+ transformedBounds(hkparam, paramowner) +" after instantiating earlier hkparams: "+ bindHKParams(transformedBounds(hkparam, paramowner)))
+ println("checkKindBoundsHK base case: "+ hkarg +" has bounds: "+ transform(hkarg.info.bounds, owner))
+ }
+ } else {
+ if(settings.debug.value) println("checkKindBoundsHK recursing to compare params of "+ hkparam +" with "+ hkarg)
+ val (am, vm, sb) = checkKindBoundsHK(hkarg.typeParams, hkarg, hkparam, paramowner, underHKParams ++ hkparam.typeParams, withHKArgs ++ hkarg.typeParams)
+ arityMismatches(am)
+ varianceMismatches(vm)
+ stricterBounds(sb)
+ }
+ if(!explainErrors && error) return (Nil, Nil, Nil) // stop as soon as we encountered an error
+ }
+ if(!explainErrors) (Nil, Nil, Nil)
+ else (_arityMismatches.toList, _varianceMismatches.toList, _stricterBounds.toList)
+ }
+ }
+
+ val errors = new ListBuffer[(Type, Symbol, List[(Symbol, Symbol)], List[(Symbol, Symbol)], List[(Symbol, Symbol)])]
+ (tparams zip targs).foreach{ case (tparam, targ) if (targ.isHigherKinded || !tparam.typeParams.isEmpty) =>
+ // @M must use the typeParams of the type targ, not the typeParams of the symbol of targ!!
+ val tparamsHO = targ.typeParams
+
+ val (arityMismatches, varianceMismatches, stricterBounds) =
+ checkKindBoundsHK(tparamsHO, targ.typeSymbolDirect, tparam, tparam.owner, tparam.typeParams, tparamsHO) // NOTE: *not* targ.typeSymbol, which normalizes
+
+ if(!explainErrors) {if(error) return List((NoType, NoSymbol, Nil, Nil, Nil))}
+ else if (arityMismatches.nonEmpty || varianceMismatches.nonEmpty || stricterBounds.nonEmpty) {
+ errors += ((targ, tparam, arityMismatches, varianceMismatches, stricterBounds))
+ }
+ // case (tparam, targ) => println("no check: "+(tparam, targ, tparam.typeParams.isEmpty))
+ case _ =>
+ }
+
+ errors.toList
+ }
+
// Errors and Diagnostics -----------------------------------------------------
/** A throwable signalling a type error */
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index f33be12bd4..52206f01de 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -228,7 +228,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast.
/** The Java signature of type 'info', for symbol sym. The symbol is used to give the right return
* type for constructors.
*/
- def javaSig(sym: Symbol, info: Type): Option[String] = atPhase(currentRun.erasurePhase) {
+ def javaSig(sym0: Symbol, info: Type): Option[String] = atPhase(currentRun.erasurePhase) {
def jsig(tp: Type): String = jsig2(false, List(), tp)
@@ -260,7 +260,11 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast.
"."+sym.name
if (sym == ArrayClass)
ARRAY_TAG.toString+(args map jsig).mkString
- else if (sym.isTypeParameterOrSkolem && !sym.owner.isTypeParameterOrSkolem /*not a higher-order type parameter, as these are suppressed*/)
+ else if (sym.isTypeParameterOrSkolem &&
+ // only refer to type params that will actually make it into the sig, this excludes:
+ !sym.owner.isTypeParameterOrSkolem && // higher-order type parameters (!sym.owner.isTypeParameterOrSkolem), and parameters of methods
+ (!sym0.isClass || sym.owner.isClass) // if we're generating the sig for a class, type params must be owned by a class (not a method -- #3249)
+ )
TVAR_TAG.toString+sym.name+";"
else if (sym == AnyClass || sym == AnyValClass || sym == SingletonClass)
jsig(ObjectClass.tpe)
@@ -302,7 +306,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast.
(if (toplevel) "<"+(tparams map paramSig).mkString+">" else "")+jsig(restpe)
case MethodType(params, restpe) =>
"("+(params map (_.tpe) map jsig).mkString+")"+
- (if (restpe.typeSymbol == UnitClass || sym.isConstructor) VOID_TAG.toString else jsig(restpe))
+ (if (restpe.typeSymbol == UnitClass || sym0.isConstructor) VOID_TAG.toString else jsig(restpe))
case RefinedType(parents, decls) if (!parents.isEmpty) =>
jsig(parents.head)
case ClassInfoType(parents, _, _) =>
@@ -310,7 +314,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast.
case AnnotatedType(_, atp, _) =>
jsig(atp)
case BoundedWildcardType(bounds) =>
- println("something's wrong: "+sym+":"+sym.tpe+" has a bounded wildcard type")
+ println("something's wrong: "+sym0+":"+sym0.tpe+" has a bounded wildcard type")
jsig(bounds.hi)
case _ =>
val etp = erasure(tp)
@@ -320,7 +324,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast.
}
if (needsJavaSig(info)) {
try {
- //println("Java sig of "+sym+" is "+jsig2(true, List(), sym.info))//DEBUG
+ //println("Java sig of "+sym0+" is "+jsig2(true, List(), sym0.info))//DEBUG
Some(jsig2(true, List(), info))
} catch {
case ex: UnknownSig => None
@@ -502,6 +506,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast.
}
/** Generate a synthetic cast operation from <code>tree.tpe</code> to <code>pt</code>.
+ * @pre pt eq pt.normalize
*/
private def cast(tree: Tree, pt: Type): Tree =
tree AS_ATTR pt
@@ -512,7 +517,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast.
/** Adapt <code>tree</code> to expected type <code>pt</code>.
*
* @param tree the given tree
- * @param pt the expected type.
+ * @param pt the expected type
* @return the adapted tree
*/
private def adaptToType(tree: Tree, pt: Type): Tree = {
@@ -928,154 +933,154 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast.
* </ul>
*/
private val preTransformer = new Transformer {
- override def transform(tree: Tree): Tree = {
- if (tree.symbol == ArrayClass && !tree.isType) return tree // !!! needed?
- val tree1 = tree match {
- case ClassDef(mods, name, tparams, impl) =>
- if (settings.debug.value)
- log("defs of " + tree.symbol + " = " + tree.symbol.info.decls)
- treeCopy.ClassDef(tree, mods, name, List(), impl)
- case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
- treeCopy.DefDef(tree, mods, name, List(), vparamss, tpt, rhs)
- case TypeDef(_, _, _, _) =>
- EmptyTree
- case Apply(instanceOf @ TypeApply(fun @ Select(qual, name), args @ List(arg)), List()) // !!! todo: simplify by having GenericArray also extract trees
- if ((fun.symbol == Any_isInstanceOf || fun.symbol == Object_isInstanceOf) &&
- unboundedGenericArrayLevel(arg.tpe) > 0) =>
- val level = unboundedGenericArrayLevel(arg.tpe)
- def isArrayTest(arg: Tree) =
- gen.mkRuntimeCall("isArray", List(arg, Literal(Constant(level))))
- typedPos(tree.pos) {
- if (level == 1) isArrayTest(qual)
- else
- gen.evalOnce(qual, currentOwner, unit) { qual1 =>
- gen.mkAnd(
- Apply(TypeApply(Select(qual1(), fun.symbol),
- List(TypeTree(erasure(arg.tpe)))),
- List()),
- isArrayTest(qual1()))
- }
- }
- case TypeApply(fun, args) if (fun.symbol.owner != AnyClass &&
- fun.symbol != Object_asInstanceOf &&
- fun.symbol != Object_isInstanceOf) =>
- // leave all other type tests/type casts, remove all other type applications
- fun
- case Apply(fn @ Select(qual, name), args) if (fn.symbol.owner == ArrayClass) =>
- if (unboundedGenericArrayLevel(qual.tpe.widen) == 1)
- // convert calls to apply/update/length on generic arrays to
- // calls of ScalaRunTime.array_xxx method calls
- typedPos(tree.pos) { gen.mkRuntimeCall("array_"+name, qual :: args) }
+ def preErase(tree: Tree): Tree = tree match {
+ case ClassDef(mods, name, tparams, impl) =>
+ if (settings.debug.value)
+ log("defs of " + tree.symbol + " = " + tree.symbol.info.decls)
+ treeCopy.ClassDef(tree, mods, name, List(), impl)
+ case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
+ treeCopy.DefDef(tree, mods, name, List(), vparamss, tpt, rhs)
+ case TypeDef(_, _, _, _) =>
+ EmptyTree
+ case Apply(instanceOf @ TypeApply(fun @ Select(qual, name), args @ List(arg)), List()) // !!! todo: simplify by having GenericArray also extract trees
+ if ((fun.symbol == Any_isInstanceOf || fun.symbol == Object_isInstanceOf) &&
+ unboundedGenericArrayLevel(arg.tpe) > 0) =>
+ val level = unboundedGenericArrayLevel(arg.tpe)
+ def isArrayTest(arg: Tree) =
+ gen.mkRuntimeCall("isArray", List(arg, Literal(Constant(level))))
+ typedPos(tree.pos) {
+ if (level == 1) isArrayTest(qual)
else
- // store exact array erasure in map to be retrieved later when we might
- // need to do the cast in adaptMember
- treeCopy.Apply(
- tree,
- SelectFromArray(qual, name, erasure(qual.tpe)).copyAttrs(fn),
- args)
+ gen.evalOnce(qual, currentOwner, unit) { qual1 =>
+ gen.mkAnd(
+ Apply(TypeApply(Select(qual1(), fun.symbol),
+ List(TypeTree(erasure(arg.tpe)))),
+ List()),
+ isArrayTest(qual1()))
+ }
+ }
+ case TypeApply(fun, args) if (fun.symbol.owner != AnyClass &&
+ fun.symbol != Object_asInstanceOf &&
+ fun.symbol != Object_isInstanceOf) =>
+ // leave all other type tests/type casts, remove all other type applications
+ preErase(fun)
+ case Apply(fn @ Select(qual, name), args) if (fn.symbol.owner == ArrayClass) =>
+ if (unboundedGenericArrayLevel(qual.tpe.widen) == 1)
+ // convert calls to apply/update/length on generic arrays to
+ // calls of ScalaRunTime.array_xxx method calls
+ typedPos(tree.pos) { gen.mkRuntimeCall("array_"+name, qual :: args) }
+ else
+ // store exact array erasure in map to be retrieved later when we might
+ // need to do the cast in adaptMember
+ treeCopy.Apply(
+ tree,
+ SelectFromArray(qual, name, erasure(qual.tpe)).copyAttrs(fn),
+ args)
- case Apply(fn @ Select(qual, _), Nil) if (fn.symbol == Any_## || fn.symbol == Object_##) =>
- Apply(gen.mkAttributedRef(scalaRuntimeHash), List(qual))
+ case Apply(fn @ Select(qual, _), Nil) if (fn.symbol == Any_## || fn.symbol == Object_##) =>
+ Apply(gen.mkAttributedRef(scalaRuntimeHash), List(qual))
- case Apply(fn, args) =>
- if (fn.symbol == Any_asInstanceOf)
- fn match {
- case TypeApply(Select(qual, _), List(targ)) =>
- if (qual.tpe <:< targ.tpe) {
- atPos(tree.pos) { Typed(qual, TypeTree(targ.tpe)) }
- } else if (isNumericValueClass(qual.tpe.typeSymbol) &&
- isNumericValueClass(targ.tpe.typeSymbol)) {
- // convert numeric type casts
- val cname = newTermName("to" + targ.tpe.typeSymbol.name)
- val csym = qual.tpe.member(cname)
- assert(csym != NoSymbol)
- atPos(tree.pos) { Apply(Select(qual, csym), List()) }
- } else
- tree
- }
- // todo: also handle the case where the singleton type is buried in a compound
- else if (fn.symbol == Any_isInstanceOf)
- fn match {
- case TypeApply(sel @ Select(qual, name), List(targ)) =>
- def mkIsInstanceOf(q: () => Tree)(tp: Type): Tree =
- Apply(
- TypeApply(
- Select(q(), Object_isInstanceOf) setPos sel.pos,
- List(TypeTree(tp) setPos targ.pos)) setPos fn.pos,
- List()) setPos tree.pos
- targ.tpe match {
- case SingleType(_, _) | ThisType(_) | SuperType(_, _) =>
- val cmpOp = if (targ.tpe <:< AnyValClass.tpe) Any_equals else Object_eq
+ case Apply(fn, args) =>
+ if (fn.symbol == Any_asInstanceOf)
+ fn match {
+ case TypeApply(Select(qual, _), List(targ)) =>
+ if (qual.tpe <:< targ.tpe) {
+ atPos(tree.pos) { Typed(qual, TypeTree(targ.tpe)) }
+ } else if (isNumericValueClass(qual.tpe.typeSymbol) &&
+ isNumericValueClass(targ.tpe.typeSymbol)) {
+ // convert numeric type casts
+ val cname = newTermName("to" + targ.tpe.typeSymbol.name)
+ val csym = qual.tpe.member(cname)
+ assert(csym != NoSymbol)
+ atPos(tree.pos) { Apply(Select(qual, csym), List()) }
+ } else
+ tree
+ }
+ // todo: also handle the case where the singleton type is buried in a compound
+ else if (fn.symbol == Any_isInstanceOf)
+ fn match {
+ case TypeApply(sel @ Select(qual, name), List(targ)) =>
+ def mkIsInstanceOf(q: () => Tree)(tp: Type): Tree =
+ Apply(
+ TypeApply(
+ Select(q(), Object_isInstanceOf) setPos sel.pos,
+ List(TypeTree(tp) setPos targ.pos)) setPos fn.pos,
+ List()) setPos tree.pos
+ targ.tpe match {
+ case SingleType(_, _) | ThisType(_) | SuperType(_, _) =>
+ val cmpOp = if (targ.tpe <:< AnyValClass.tpe) Any_equals else Object_eq
+ atPos(tree.pos) {
+ Apply(Select(qual, cmpOp), List(gen.mkAttributedQualifier(targ.tpe)))
+ }
+ case RefinedType(parents, decls) if (parents.length >= 2) =>
+ gen.evalOnce(qual, currentOwner, unit) { q =>
atPos(tree.pos) {
- Apply(Select(qual, cmpOp), List(gen.mkAttributedQualifier(targ.tpe)))
- }
- case RefinedType(parents, decls) if (parents.length >= 2) =>
- gen.evalOnce(qual, currentOwner, unit) { q =>
- atPos(tree.pos) {
- parents map mkIsInstanceOf(q) reduceRight gen.mkAnd
- }
+ parents map mkIsInstanceOf(q) reduceRight gen.mkAnd
}
- case _ =>
- tree
- }
- case _ => tree
- }
- else {
- def doDynamic(fn: Tree, qual: Tree): Tree = {
- if (fn.symbol.owner.isRefinementClass && fn.symbol.allOverriddenSymbols.isEmpty)
- ApplyDynamic(qual, args) setSymbol fn.symbol setPos tree.pos
- else tree
- }
- fn match {
- case Select(qual, _) => doDynamic(fn, qual)
- case TypeApply(fni@Select(qual, _), _) => doDynamic(fni, qual)// type parameters are irrelevant in case of dynamic call
- case _ =>
- tree
- }
+ }
+ case _ =>
+ tree
+ }
+ case _ => tree
}
-
- case Select(_, _) =>
- if (tree.symbol.owner.isRefinementClass) {
- val overridden = tree.symbol.allOverriddenSymbols
- assert(!overridden.isEmpty, tree.symbol)
- tree.symbol = overridden.head
+ else {
+ def doDynamic(fn: Tree, qual: Tree): Tree = {
+ if (fn.symbol.owner.isRefinementClass && fn.symbol.allOverriddenSymbols.isEmpty)
+ ApplyDynamic(qual, args) setSymbol fn.symbol setPos tree.pos
+ else tree
}
- tree
+ fn match {
+ case Select(qual, _) => doDynamic(fn, qual)
+ case TypeApply(fni@Select(qual, _), _) => doDynamic(fni, qual)// type parameters are irrelevant in case of dynamic call
+ case _ =>
+ tree
+ }
+ }
- case Template(parents, self, body) =>
- assert(!currentOwner.isImplClass)
- //Console.println("checking no dble defs " + tree)//DEBUG
- checkNoDoubleDefs(tree.symbol.owner)
- treeCopy.Template(tree, parents, emptyValDef, addBridges(body, currentOwner))
+ case Select(_, _) =>
+ // println("preXform: "+ (tree, tree.symbol, tree.symbol.owner, tree.symbol.owner.isRefinementClass))
+ if (tree.symbol.owner.isRefinementClass) {
+ val overridden = tree.symbol.allOverriddenSymbols
+ assert(!overridden.isEmpty, tree.symbol)
+ tree.symbol = overridden.head
+ }
+ tree
- case Match(selector, cases) =>
- Match(Typed(selector, TypeTree(selector.tpe)), cases)
+ case Template(parents, self, body) =>
+ assert(!currentOwner.isImplClass)
+ //Console.println("checking no dble defs " + tree)//DEBUG
+ checkNoDoubleDefs(tree.symbol.owner)
+ treeCopy.Template(tree, parents, emptyValDef, addBridges(body, currentOwner))
- case Literal(ct) if ct.tag == ClassTag
- && ct.typeValue.typeSymbol != definitions.UnitClass =>
- treeCopy.Literal(tree, Constant(erasure(ct.typeValue)))
+ case Match(selector, cases) =>
+ Match(Typed(selector, TypeTree(selector.tpe)), cases)
- case _ =>
- tree
- }
- tree1 match {
- case EmptyTree | TypeTree() =>
- tree1 setType erasure(tree1.tpe)
- case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
- val result = super.transform(tree1) setType null
- tpt.tpe = erasure(tree.symbol.tpe).resultType
- result
- case _ =>
- case class LoopControl(count: Int, ex : AssertionError) extends Throwable(ex.getMessage) with ControlThrowable
+ case Literal(ct) if ct.tag == ClassTag
+ && ct.typeValue.typeSymbol != definitions.UnitClass =>
+ treeCopy.Literal(tree, Constant(erasure(ct.typeValue)))
- try super.transform(tree1) setType null
- catch {
- case LoopControl(n, ex) if n <= 5 =>
- Console.println(tree1)
- throw LoopControl(n + 1, ex)
- }
- }
+ case _ =>
+ tree
}
+
+ override def transform(tree: Tree): Tree =
+ if (tree.symbol == ArrayClass && !tree.isType) tree // !!! needed?
+ else {
+ val tree1 = preErase(tree)
+ // println("preErase: "+ tree +" = "+ tree1)
+ val res = tree1 match {
+ case EmptyTree | TypeTree() =>
+ tree1 setType erasure(tree1.tpe)
+ case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
+ val result = super.transform(tree1) setType null
+ tpt.tpe = erasure(tree1.symbol.tpe).resultType
+ result
+ case _ =>
+ super.transform(tree1) setType null
+ }
+ // println("xform: "+ res)
+ res
+ }
}
/** The main transform function: Pretransfom the tree, and then
@@ -1090,4 +1095,4 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast.
}
}
}
-}
+} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index c228ee0e46..d1b3142c8a 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -231,12 +231,27 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
for (member <- impl.info.decls.toList) {
if (isForwarded(member)) {
val imember = member.overriddenSymbol(iface)
- //Console.println("mixin member "+member+":"+member.tpe+member.locationString+" "+imember+" "+imember.overridingSymbol(clazz)+" to "+clazz+" with scope "+clazz.info.decls)//DEBUG
+ // atPhase(currentRun.erasurePhase){
+ // println(""+(clazz, iface, clazz.typeParams, iface.typeParams, imember, clazz.thisType.baseType(iface), clazz.thisType.baseType(iface).memberInfo(imember), imember.info substSym(iface.typeParams, clazz.typeParams) ))
+ // }
+ // Console.println("mixin member "+member+":"+member.tpe+member.locationString+" "+imember+" "+imember.overridingSymbol(clazz)+" to "+clazz+" with scope "+clazz.info.decls)//DEBUG
if (imember.overridingSymbol(clazz) == NoSymbol &&
clazz.info.findMember(member.name, 0, lateDEFERRED, false).alternatives.contains(imember)) {
+ val newSym = atPhase(currentRun.erasurePhase){
+ val res = imember.cloneSymbol(clazz)
+ // since we used the member (imember) from the interface that represents the trait that's being mixed in,
+ // have to instantiate the interface type params (that may occur in imember's info) as they are seen from the class
+ // we can't use the member that we get from the implementation class, as it's a clone that was made after erasure,
+ // and thus it does not know its info at the beginning of erasure anymore
+ // optimize: no need if iface has no typeparams
+ if(iface.typeParams nonEmpty) res.setInfo(clazz.thisType.baseType(iface).memberInfo(imember))
+ res
+ } // clone before erasure got rid of type info we'll need to generate a javaSig
+ // now we'll have the type info at (the beginning of) erasure in our history,
+ newSym.updateInfo(imember.info.cloneInfo(newSym)) // and now newSym has the info that's been transformed to fit this period (no need for asSeenFrom as phase.erasedTypes)
val member1 = addMember(
clazz,
- member.cloneSymbol(clazz) setPos clazz.pos resetFlag (DEFERRED | lateDEFERRED))
+ newSym setPos clazz.pos resetFlag (DEFERRED | lateDEFERRED))
member1.asInstanceOf[TermSymbol] setAlias member;
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala b/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala
index 6656b79d26..de5355de61 100644
--- a/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala
+++ b/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala
@@ -26,7 +26,7 @@ trait TypingTransformers {
protected def typedPos(pos: Position)(tree: Tree) = localTyper typed { atPos(pos)(tree) }
/** a typer for each enclosing class */
- var typers: Map[Symbol, analyzer.Typer] = new HashMap
+ val typers: Map[Symbol, analyzer.Typer] = new HashMap
override def atOwner[A](owner: Symbol)(trans: => A): A = atOwner(curTree, owner)(trans)
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 0270323133..8e3722dd99 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -62,6 +62,8 @@ abstract class UnCurry extends InfoTransform with TypingTransformers {
case MethodType(params, ExistentialType(tparams, restpe @ MethodType(_, _))) =>
assert(false, "unexpected curried method types with intervening existential")
tp0
+ case MethodType(h :: t, restpe) if h.isImplicit =>
+ apply(MethodType(h.cloneSymbol.resetFlag(IMPLICIT) :: t, restpe))
case PolyType(List(), restpe) => // nullary method type
apply(MethodType(List(), restpe))
case PolyType(tparams, restpe) => // polymorphic nullary method type, since it didn't occur in a higher-kinded position
@@ -398,7 +400,7 @@ abstract class UnCurry extends InfoTransform with TypingTransformers {
val predef = gen.mkAttributedRef(PredefModule)
val meth =
if ((elemtp <:< AnyRefClass.tpe) && !isPhantomClass(elemtp.typeSymbol))
- Select(predef, "wrapRefArray")
+ TypeApply(Select(predef, "wrapRefArray"), List(TypeTree(elemtp)))
else if (isValueClass(elemtp.typeSymbol))
Select(predef, "wrap"+elemtp.typeSymbol.name+"Array")
else
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index 7469388a08..42c1329edf 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -8,6 +8,7 @@ package typechecker
import symtab.Flags._
import scala.collection.mutable.ListBuffer
+import annotation.tailrec
/** This trait ...
*
@@ -349,9 +350,26 @@ trait Contexts { self: Analyzer =>
* @return ...
*/
def isAccessible(sym: Symbol, pre: Type, superAccess: Boolean): Boolean = {
+ @inline def accessWithinLinked(ab: Symbol) = {
+ val linked = ab.linkedClassOfClass
+ // don't have access if there is no linked class
+ // (before adding the `ne NoSymbol` check, this was a no-op when linked eq NoSymbol,
+ // since `accessWithin(NoSymbol) == true` whatever the symbol)
+ (linked ne NoSymbol) && accessWithin(linked)
+ }
+
+ /** Are we inside definition of `ab'? */
+ def accessWithin(ab: Symbol) = {
+ // #3663: we must disregard package nesting if sym isJavaDefined
+ if(sym.isJavaDefined) {
+ // is `o` or one of its transitive owners equal to `ab`?
+ // stops at first package, since further owners can only be surrounding packages
+ @tailrec def abEnclosesStopAtPkg(o: Symbol): Boolean =
+ (o eq ab) || (!o.isPackageClass && (o ne NoSymbol) && abEnclosesStopAtPkg(o.owner))
+ abEnclosesStopAtPkg(owner)
+ } else (owner hasTransOwner ab)
+ }
- /** Are we inside definition of `sym'? */
- def accessWithin(sym: Symbol): Boolean = this.owner.ownersIterator contains sym
/*
var c = this
while (c != NoContext && c.owner != owner) {
@@ -373,18 +391,20 @@ trait Contexts { self: Analyzer =>
(pre == NoPrefix) || {
val ab = sym.accessBoundary(sym.owner)
- ((ab.isTerm || ab == definitions.RootClass)
- ||
- (accessWithin(ab) || accessWithin(ab.linkedClassOfClass)) &&
- (!sym.hasFlag(LOCAL) ||
- sym.owner.isImplClass || // allow private local accesses to impl classes
- (sym hasFlag PROTECTED) && isSubThisType(pre, sym.owner) ||
- pre =:= sym.owner.thisType)
- ||
- (sym hasFlag PROTECTED) &&
- (superAccess || sym.isConstructor ||
- (pre.widen.typeSymbol.isNonBottomSubClass(sym.owner) &&
- (isSubClassOfEnclosing(pre.widen.typeSymbol) || phase.erasedTypes))))
+ ( (ab.isTerm || ab == definitions.RootClass)
+ || (accessWithin(ab) || accessWithinLinked(ab)) &&
+ ( !sym.hasFlag(LOCAL)
+ || sym.owner.isImplClass // allow private local accesses to impl classes
+ || (sym hasFlag PROTECTED) && isSubThisType(pre, sym.owner)
+ || pre =:= sym.owner.thisType
+ )
+ || (sym hasFlag PROTECTED) &&
+ ( superAccess
+ || sym.isConstructor
+ || (pre.widen.typeSymbol.isNonBottomSubClass(sym.owner) &&
+ (isSubClassOfEnclosing(pre.widen.typeSymbol) || phase.erasedTypes))
+ )
+ )
// note: phase.erasedTypes disables last test, because after addinterfaces
// implementation classes are not in the superclass chain. If we enable the
// test, bug780 fails.
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 3abaf4f337..0056dcd917 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -27,6 +27,7 @@ self: Analyzer =>
import definitions._
def traceImplicits = printTypings
+ import global.typer.{printTyping, deindentTyping, indentTyping}
/** Search for an implicit value. See the comment on `result` at the end of class `ImplicitSearch`
* for more info how the search is conducted.
@@ -42,6 +43,8 @@ self: Analyzer =>
* @return A search result
*/
def inferImplicit(tree: Tree, pt: Type, reportAmbiguous: Boolean, isView: Boolean, context: Context): SearchResult = {
+ printTyping("Beginning implicit search for "+ tree +" expecting "+ pt + (if(isView) " looking for a view" else ""))
+ indentTyping()
val rawTypeStart = startCounter(rawTypeImpl)
val findMemberStart = startCounter(findMemberImpl)
val subtypeStart = startCounter(subtypeImpl)
@@ -54,6 +57,8 @@ self: Analyzer =>
stopCounter(rawTypeImpl, rawTypeStart)
stopCounter(findMemberImpl, findMemberStart)
stopCounter(subtypeImpl, subtypeStart)
+ deindentTyping()
+ printTyping("Implicit search yielded: "+ result)
result
}
@@ -209,11 +214,10 @@ self: Analyzer =>
*/
class ImplicitSearch(tree: Tree, pt: Type, isView: Boolean, context0: Context)
extends Typer(context0) {
-
+ printTyping("begin implicit search: "+(tree, pt, isView, context.outer.undetparams))
// assert(tree.isEmpty || tree.pos.isDefined, tree)
import infer._
-
/** Is implicit info `info1` better than implicit info `info2`?
*/
def improves(info1: ImplicitInfo, info2: ImplicitInfo) = {
@@ -424,7 +428,7 @@ self: Analyzer =>
incCounter(plausiblyCompatibleImplicits)
- //if (traceImplicits) println("typed impl for "+wildPt+"? "+info.name+":"+depoly(info.tpe)+"/"+undetParams+"/"+isPlausiblyCompatible(info.tpe, wildPt)+"/"+matchesPt(depoly(info.tpe), wildPt, List())+"/"+info.pre+"/"+isStable(info.pre))
+ printTyping("typed impl for "+wildPt+"? "+info.name +":"+ depoly(info.tpe)+ " orig info= "+ info.tpe +"/"+undetParams+"/"+isPlausiblyCompatible(info.tpe, wildPt)+"/"+matchesPt(depoly(info.tpe), wildPt, List())+"/"+info.pre+"/"+isStable(info.pre))
if (matchesPt(depoly(info.tpe), wildPt, List()) && isStable(info.pre)) {
incCounter(matchingImplicits)
@@ -433,7 +437,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 pt = "+pt+", wildpt = "+wildPt)
+ printTyping("typedImplicit0 typing"+ itree +" with wildpt = "+ wildPt +" from implicit "+ info.name+":"+info.tpe)
def fail(reason: String): SearchResult = {
if (settings.XlogImplicits.value)
inform(itree+" is not a valid implicit value for "+pt+" because:\n"+reason)
@@ -452,10 +456,10 @@ self: Analyzer =>
incCounter(typedImplicits)
- if (traceImplicits) println("typed implicit "+itree1+":"+itree1.tpe+", pt = "+wildPt)
+ printTyping("typed implicit "+itree1+":"+itree1.tpe+", pt = "+wildPt)
val itree2 = if (isView) (itree1: @unchecked) match { case Apply(fun, _) => fun }
else adapt(itree1, EXPRmode, wildPt)
- if (traceImplicits) println("adapted implicit "+itree1.symbol+":"+itree2.tpe+" to "+wildPt)
+ printTyping("adapted implicit "+itree1.symbol+":"+itree2.tpe+" to "+wildPt)
def hasMatchingSymbol(tree: Tree): Boolean = (tree.symbol == info.sym) || {
tree match {
case Apply(fun, _) => hasMatchingSymbol(fun)
@@ -469,7 +473,7 @@ self: Analyzer =>
else if (hasMatchingSymbol(itree1)) {
val tvars = undetParams map freshVar
if (matchesPt(itree2.tpe, pt.instantiateTypeParams(undetParams, tvars), undetParams)) {
- if (traceImplicits) println("tvars = "+tvars+"/"+(tvars map (_.constr)))
+ printTyping("tvars = "+tvars+"/"+(tvars map (_.constr)))
val targs = solvedTypes(tvars, undetParams, undetParams map varianceInType(pt),
false, lubDepth(List(itree2.tpe, pt)))
@@ -478,7 +482,7 @@ self: Analyzer =>
// filter out failures from type inference, don't want to remove them from undetParams!
// we must be conservative in leaving type params in undetparams
- val (okParams, okArgs, _) = adjustTypeArgs(undetParams, targs) // prototype == WildcardType: want to remove all inferred Nothing's
+ val AdjustedTypeArgs(okParams, okArgs) = adjustTypeArgs(undetParams, targs) // prototype == WildcardType: want to remove all inferred Nothing's
val subst = new TreeTypeSubstituter(okParams, okArgs)
subst traverse itree2
@@ -498,7 +502,8 @@ self: Analyzer =>
// println("RESULT = "+itree+"///"+itree1+"///"+itree2)//DEBUG
result
} else {
- if (traceImplicits) println("incompatible: "+itree2.tpe+" does not match "+pt.instantiateTypeParams(undetParams, tvars))
+ printTyping("incompatible: "+itree2.tpe+" does not match "+pt.instantiateTypeParams(undetParams, tvars))
+
SearchFailure
}
} else if (settings.XlogImplicits.value)
@@ -810,7 +815,7 @@ self: Analyzer =>
def mot(tp0: Type): Tree = {
val tp1 = tp0.normalize
tp1 match {
- case ThisType(_) | SingleType(_, _) =>
+ case ThisType(_) | SingleType(_, _) if !(tp1 exists {tp => tp.typeSymbol.isExistentiallyBound}) => // can't generate a reference to a value that's abstracted over by an existential
manifestFactoryCall("singleType", tp, gen.mkAttributedQualifier(tp1))
case ConstantType(value) =>
manifestOfType(tp1.deconst, full)
@@ -840,6 +845,8 @@ self: Analyzer =>
} else if (sym.isExistentiallyBound && full) {
manifestFactoryCall("wildcardType", tp,
findManifest(tp.bounds.lo), findManifest(tp.bounds.hi))
+ } else if(undetParams contains sym) { // looking for a manifest of a type parameter that hasn't been inferred by now, can't do much, but let's not fail
+ mot(NothingClass.tpe) // TODO: should we include the mapping from sym -> NothingClass.tpe in the SearchResult? (it'll get instantiated to nothing anyway, I think)
} else {
EmptyTree // a manifest should have been found by normal searchImplicit
}
@@ -924,5 +931,46 @@ self: Analyzer =>
}
}
+ object ImplicitNotFoundMsg {
+ def unapply(sym: Symbol): Option[(Message)] = sym.implicitNotFoundMsg map (m => (new Message(sym, m)))
+ // check the message's syntax: should be a string literal that may contain occurences of the string "${X}",
+ // where `X` refers to a type parameter of `sym`
+ def check(sym: Symbol): Option[String] =
+ sym.getAnnotation(ImplicitNotFoundClass).flatMap(_.stringArg(0) match {
+ case Some(m) => new Message(sym, m) validate
+ case None => Some("Missing argument `msg` on implicitNotFound annotation.")
+ })
+
+
+ class Message(sym: Symbol, msg: String) {
+ // http://dcsobral.blogspot.com/2010/01/string-interpolation-in-scala-with.html
+ private def interpolate(text: String, vars: Map[String, String]) = { import scala.util.matching.Regex
+ """\$\{([^}]+)\}""".r.replaceAllIn(text, (_: Regex.Match) match {
+ case Regex.Groups(v) => vars.getOrElse(v, "")
+ })}
+
+ private lazy val typeParamNames: List[String] = sym.typeParams.map(_.decodedName)
+
+ def format(paramName: Name, paramTp: Type): String = format(paramTp.typeArgs map (_.toString))
+ def format(typeArgs: List[String]): String =
+ interpolate(msg, Map((typeParamNames zip typeArgs): _*)) // TODO: give access to the name and type of the implicit argument, etc?
+
+ def validate: Option[String] = {
+ import scala.util.matching.Regex; import collection.breakOut
+ // is there a shorter way to avoid the intermediate toList?
+ val refs = Set("""\$\{([^}]+)\}""".r.findAllIn(msg).matchData.map(_.group(1)).toList : _*)
+ val decls = Set(typeParamNames : _*)
+ (refs &~ decls) match {
+ case s if s isEmpty => None
+ case unboundNames =>
+ val singular = unboundNames.size == 1
+ Some("The type parameter"+( if(singular) " " else "s " )+ unboundNames.mkString(", ") +
+ " referenced in the message of the @implicitNotFound annotation "+( if(singular) "is" else "are" )+
+ " not defined by "+ sym +".")
+ }
+ }
+ }
+ }
+
private val DivergentImplicit = new Exception()
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 89346cbdab..a02f384a8d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -242,6 +242,9 @@ trait Infer {
/** Check that <code>sym</code> is defined and accessible as a member of
* tree <code>site</code> with type <code>pre</code> in current context.
+ *
+ * Note: pre is not refchecked -- moreover, refchecking the resulting tree may not refcheck pre,
+ * since pre may not occur in its type (callers should wrap the result in a TypeTreeWithDeferredRefCheck)
*/
def checkAccessible(tree: Tree, sym: Symbol, pre: Type, site: Tree): Tree =
if (sym.isError) {
@@ -515,48 +518,64 @@ trait Infer {
tvars map (tvar => WildcardType)
}
+ object AdjustedTypeArgs {
+ type Result = collection.mutable.LinkedHashMap[Symbol, Option[Type]]
+
+ def unapply(m: Result): Some[(List[Symbol], List[Type])] = Some(toLists(
+ m collect {case (p, Some(a)) => (p, a)} unzip ))
+
+ object Undets {
+ def unapply(m: Result): Some[(List[Symbol], List[Type], List[Symbol])] = Some(toLists{
+ val (ok, nok) = m.map{case (p, a) => (p, a.getOrElse(null))}.partition(_._2 ne null)
+ val (okArgs, okTparams) = ok.unzip
+ (okArgs, okTparams, nok.keys)
+ })
+ }
+
+ object AllArgsAndUndets {
+ def unapply(m: Result): Some[(List[Symbol], List[Type], List[Type], List[Symbol])] = Some(toLists{
+ val (ok, nok) = m.map{case (p, a) => (p, a.getOrElse(null))}.partition(_._2 ne null)
+ val (okArgs, okTparams) = ok.unzip
+ (okArgs, okTparams, m.values.map(_.getOrElse(NothingClass.tpe)), nok.keys)
+ })
+ }
+
+ @inline private def toLists[A1, A2](pxs: (Iterable[A1], Iterable[A2])) = (pxs._1.toList, pxs._2.toList)
+ @inline private def toLists[A1, A2, A3](pxs: (Iterable[A1], Iterable[A2], Iterable[A3])) = (pxs._1.toList, pxs._2.toList, pxs._3.toList)
+ @inline private def toLists[A1, A2, A3, A4](pxs: (Iterable[A1], Iterable[A2], Iterable[A3], Iterable[A4])) = (pxs._1.toList, pxs._2.toList, pxs._3.toList, pxs._4.toList)
+ }
+
/** Retract arguments that were inferred to Nothing because inference failed. Correct types for repeated params.
*
* We detect Nothing-due-to-failure by only retracting a parameter if either:
* - it occurs in an invariant/contravariant position in `restpe`
* - `restpe == WildcardType`
*
- * Retracted parameters are collected in `uninstantiated`.
+ * Retracted parameters are mapped to None.
+ * TODO:
+ * - make sure the performance hit of storing these in a map is acceptable (it's going to be a small map in 90% of the cases, I think)
+ * - refactor further up the callstack so that we don't have to do this post-factum adjustment?
*
* Rewrite for repeated param types: Map T* entries to Seq[T].
- * @return (okTparams, okArgs, leftUndet)
- * * okTparams, okArgs: lists of tparam symbols and their inferred types
- * * leftUndet a list of remaining uninstantiated type parameters after inference
- * (type parameters mapped by the constraint solver to `scala.Nothing'
- * and not covariant in <code>restpe</code> are taken to be
- * uninstantiated. Maps all those type arguments to their
- * corresponding type parameters).
+ * @return map from tparams to inferred arg, if inference was successful, tparams that map to None are considered left undetermined
+ * type parameters that are inferred as `scala.Nothing' and that are not covariant in <code>restpe</code> are taken to be undetermined
*/
- def adjustTypeArgs(tparams: List[Symbol], targs: List[Type], restpe: Type = WildcardType): (List[Symbol], List[Type], List[Symbol]) = {
+ def adjustTypeArgs(tparams: List[Symbol], targs: List[Type], restpe: Type = WildcardType): AdjustedTypeArgs.Result = {
@inline def notCovariantIn(tparam: Symbol, restpe: Type) =
(varianceInType(restpe)(tparam) & COVARIANT) == 0 // tparam occurred non-covariantly (in invariant or contravariant position)
- val leftUndet = new ListBuffer[Symbol]
- val okParams = new ListBuffer[Symbol]
- val okArgs = new ListBuffer[Type]
-
- (tparams, targs).zipped foreach { (tparam, targ) =>
+ (tparams, targs).zipped.map{ (tparam, targ) =>
if (targ.typeSymbol == NothingClass &&
(isWildcard(restpe) || notCovariantIn(tparam, restpe))) {
- leftUndet += tparam
- // don't add anything to okArgs, it'll be filtered out later anyway
- // used `tparam.tpeHK` as dummy before
+ tparam -> None
} else {
- okParams += tparam
- okArgs += (
+ tparam -> Some(
if (targ.typeSymbol == RepeatedParamClass) targ.baseType(SeqClass)
else if (targ.typeSymbol == JavaRepeatedParamClass) targ.baseType(ArrayClass)
else targ.widen
)
}
- }
-
- (okParams.toList, okArgs.toList, leftUndet.toList)
+ }(collection.breakOut)
}
/** Return inferred type arguments, given type parameters, formal parameters,
@@ -572,18 +591,12 @@ trait Infer {
* @param restp the result type of the method
* @param argtpes the argument types of the application
* @param pt the expected return type of the application
- * @return (okTparams, okArgs, leftUndet)
- * * okTparams, okArgs: lists of tparam symbols and their inferred types
- * * leftUndet a list of remaining uninstantiated type parameters after inference
- * (type parameters mapped by the constraint solver to `scala.Nothing'
- * and not covariant in <code>restpe</code> are taken to be
- * uninstantiated. Maps all those type arguments to their
- * corresponding type parameters).
+ * @return @see adjustTypeArgs
* @throws NoInstance
*/
def methTypeArgs(tparams: List[Symbol], formals: List[Type], restpe: Type,
- argtpes: List[Type], pt: Type): (List[Symbol], List[Type], List[Symbol]) = {
+ argtpes: List[Type], pt: Type): AdjustedTypeArgs.Result = {
val tvars = tparams map freshVar
if (inferInfo)
println("methTypeArgs tparams = "+tparams+
@@ -757,7 +770,7 @@ trait Infer {
isCompatibleArgs(argtpes, formals) && isWeaklyCompatible(restpe, pt)
} else {
try {
- val (okparams, okargs, leftUndet) = methTypeArgs(undetparams, formals, restpe, argtpes, pt)
+ val AdjustedTypeArgs.Undets(okparams, okargs, leftUndet) = methTypeArgs(undetparams, formals, restpe, argtpes, pt)
// #2665: must use weak conformance, not regular one (follow the monomorphic case above)
(exprTypeArgs(leftUndet, restpe.instantiateTypeParams(okparams, okargs), pt, isWeaklyCompatible) ne null) &&
isWithinBounds(NoPrefix, NoSymbol, okparams, okargs)
@@ -1010,71 +1023,8 @@ trait Infer {
}
}
- /** Check whether <arg>sym1</arg>'s variance conforms to <arg>sym2</arg>'s variance
- *
- * If <arg>sym2</arg> is invariant, <arg>sym1</arg>'s variance is irrelevant. Otherwise they must be equal.
- */
- def variancesMatch(sym1: Symbol, sym2: Symbol): Boolean = (sym2.variance==0 || sym1.variance==sym2.variance)
- /** Check well-kindedness of type application (assumes arities are already checked) -- @M
- *
- * This check is also performed when abstract type members become concrete (aka a "type alias") -- then tparams.length==1
- * (checked one type member at a time -- in that case, prefix is the name of the type alias)
- *
- * Type application is just like value application: it's "contravariant" in the sense that
- * the type parameters of the supplied type arguments must conform to the type parameters of
- * the required type parameters:
- * - their bounds must be less strict
- * - variances must match (here, variances are absolute, the variance of a type parameter does not influence the variance of its higher-order parameters)
- * - @M TODO: are these conditions correct,sufficient&necessary?
- *
- * e.g. class Iterable[t, m[+x <: t]] --> the application Iterable[Int, List] is okay, since
- * List's type parameter is also covariant and its bounds are weaker than <: Int
- */
def checkKindBounds(tparams: List[Symbol], targs: List[Type], pre: Type, owner: Symbol): List[String] = {
- def transform(tp: Type, clazz: Symbol): Type = tp.asSeenFrom(pre, clazz) // instantiate type params that come from outside the abstract type we're currently checking
-
- // check that the type parameters <arg>hkargs</arg> to a higher-kinded type conform to the expected params <arg>hkparams</arg>
- def checkKindBoundsHK(hkargs: List[Symbol], arg: Symbol, param: Symbol, paramowner: Symbol): (List[(Symbol, Symbol)], List[(Symbol, Symbol)], List[(Symbol, Symbol)]) = {
- // @M sometimes hkargs != arg.typeParams, the symbol and the type may have very different type parameters
- val hkparams = param.typeParams
-
- if(hkargs.length != hkparams.length) {
- if(arg == AnyClass || arg == NothingClass) (Nil, Nil, Nil) // Any and Nothing are kind-overloaded
- else (List((arg, param)), Nil, Nil)
- } else {
- val _arityMismatches = new ListBuffer[(Symbol, Symbol)]
- val _varianceMismatches = new ListBuffer[(Symbol, Symbol)]
- val _stricterBounds = new ListBuffer[(Symbol, Symbol)]
- def varianceMismatch(a: Symbol, p: Symbol) { _varianceMismatches += ((a, p)) }
- def stricterBound(a: Symbol, p: Symbol) { _stricterBounds += ((a, p)) }
- def arityMismatches(as: Iterable[(Symbol, Symbol)]) { _arityMismatches ++= as }
- def varianceMismatches(as: Iterable[(Symbol, Symbol)]) { _varianceMismatches ++= as }
- def stricterBounds(as: Iterable[(Symbol, Symbol)]) { _stricterBounds ++= as }
-
- for ((hkarg, hkparam) <- hkargs zip hkparams) {
- if (hkparam.typeParams.isEmpty) { // base-case: kind *
- if (!variancesMatch(hkarg, hkparam))
- varianceMismatch(hkarg, hkparam)
-
- // instantiateTypeParams(tparams, targs) --> higher-order bounds may contain references to type arguments
- // substSym(hkparams, hkargs) --> these types are going to be compared as types of kind *
- // --> their arguments use different symbols, but are conceptually the same
- // (could also replace the types by polytypes, but can't just strip the symbols, as ordering is lost then)
- if (!(transform(hkparam.info.instantiateTypeParams(tparams, targs).bounds.substSym(hkparams, hkargs), paramowner) <:< transform(hkarg.info.bounds, owner)))
- stricterBound(hkarg, hkparam)
- } else {
- val (am, vm, sb) = checkKindBoundsHK(hkarg.typeParams, hkarg, hkparam, paramowner)
- arityMismatches(am)
- varianceMismatches(vm)
- stricterBounds(sb)
- }
- }
-
- (_arityMismatches.toList, _varianceMismatches.toList, _stricterBounds.toList)
- }
- }
-
// @M TODO this method is duplicated all over the place (varianceString)
def varStr(s: Symbol): String =
if (s.isCovariant) "covariant"
@@ -1090,32 +1040,22 @@ trait Infer {
}
}
- val errors = new ListBuffer[String]
- (tparams zip targs).foreach{ case (tparam, targ) if (targ.isHigherKinded || !tparam.typeParams.isEmpty) =>
- // @M must use the typeParams of the type targ, not the typeParams of the symbol of targ!!
- val tparamsHO = targ.typeParams
-
- val (arityMismatches, varianceMismatches, stricterBounds) =
- checkKindBoundsHK(tparamsHO, targ.typeSymbolDirect, tparam, tparam.owner) // NOTE: *not* targ.typeSymbol, which normalizes
- if (!(arityMismatches.isEmpty && varianceMismatches.isEmpty && stricterBounds.isEmpty)){
- errors += (targ+"'s type parameters do not match "+tparam+"'s expected parameters: "+
- (for ((a, p) <- arityMismatches)
- yield a+qualify(a,p)+ " has "+reporter.countElementsAsString(a.typeParams.length, "type parameter")+", but "+
- p+qualify(p,a)+" has "+reporter.countAsString(p.typeParams.length)).toList.mkString(", ") +
- (for ((a, p) <- varianceMismatches)
- yield a+qualify(a,p)+ " is "+varStr(a)+", but "+
- p+qualify(p,a)+" is declared "+varStr(p)).toList.mkString(", ") +
- (for ((a, p) <- stricterBounds)
- yield a+qualify(a,p)+"'s bounds "+a.info+" are stricter than "+
- p+qualify(p,a)+"'s declared bounds "+p.info).toList.mkString(", "))
- }
- // case (tparam, targ) => println("no check: "+(tparam, targ, tparam.typeParams.isEmpty))
- case _ =>
+ val errors = checkKindBounds0(tparams, targs, pre, owner, true)
+ val errorMessages = new ListBuffer[String]
+ errors foreach {case (targ, tparam, arityMismatches, varianceMismatches, stricterBounds) => errorMessages +=
+ (targ+"'s type parameters do not match "+tparam+"'s expected parameters: "+
+ (for ((a, p) <- arityMismatches)
+ yield a+qualify(a,p)+ " has "+reporter.countElementsAsString(a.typeParams.length, "type parameter")+", but "+
+ p+qualify(p,a)+" has "+reporter.countAsString(p.typeParams.length)).toList.mkString(", ") +
+ (for ((a, p) <- varianceMismatches)
+ yield a+qualify(a,p)+ " is "+varStr(a)+", but "+
+ p+qualify(p,a)+" is declared "+varStr(p)).toList.mkString(", ") +
+ (for ((a, p) <- stricterBounds)
+ yield a+qualify(a,p)+"'s bounds "+a.info+" are stricter than "+
+ p+qualify(p,a)+"'s declared bounds "+p.info).toList.mkString(", "))
}
-
- errors.toList
+ errorMessages.toList
}
-
/** Substitite free type variables `undetparams' of polymorphic argument
* expression `tree', given two prototypes `strictPt', and `lenientPt'.
* `strictPt' is the first attempt prototype where type parameters
@@ -1151,14 +1091,16 @@ trait Infer {
" tparams = "+tparams+"\n"+
" pt = "+pt)
val targs = exprTypeArgs(tparams, tree.tpe, pt)
- val (okParams, okArgs, leftUndet) = // TODO AM: is this pattern match too expensive? should we push it down into the else of the if below?
- if (keepNothings || (targs eq null)) (tparams, targs, List()) //@M: adjustTypeArgs fails if targs==null, neg/t0226
- else adjustTypeArgs(tparams, targs)
-
- if (inferInfo) println("inferred expr instance for "+ tree +" --> (okParams, okArgs, leftUndet)= "+(okParams, okArgs, leftUndet))
- substExpr(tree, okParams, okArgs, pt)
- leftUndet
+ if (keepNothings || (targs eq null)) { //@M: adjustTypeArgs fails if targs==null, neg/t0226
+ substExpr(tree, tparams, targs, pt)
+ List()
+ } else {
+ val AdjustedTypeArgs.Undets(okParams, okArgs, leftUndet) = adjustTypeArgs(tparams, targs)
+ if (inferInfo) println("inferred expr instance for "+ tree +" --> (okParams, okArgs, leftUndet)= "+(okParams, okArgs, leftUndet))
+ substExpr(tree, okParams, okArgs, pt)
+ leftUndet
+ }
}
/** Substitite free type variables `undetparams' of polymorphic argument
@@ -1180,14 +1122,15 @@ trait Infer {
}
}
- /** Substitite free type variables <code>undetparams</code> of application
+ /** Substitute free type variables <code>undetparams</code> of application
* <code>fn(args)</code>, given prototype <code>pt</code>.
*
* @param fn ...
* @param undetparams ...
* @param args ...
* @param pt ...
- * @return Return the list of type parameters that remain uninstantiated.
+ * @return The type parameters that remain uninstantiated,
+ * and that thus have not been substituted.
*/
def inferMethodInstance(fn: Tree, undetparams: List[Symbol],
args: List[Tree], pt0: Type): List[Symbol] = fn.tpe match {
@@ -1202,8 +1145,8 @@ trait Infer {
val formals = formalTypes(params0 map (_.tpe), args.length)
val argtpes = actualTypes(args map (_.tpe.deconst), formals.length)
val restpe = fn.tpe.resultType(argtpes)
- val (okparams, okargs, leftUndet) = methTypeArgs(undetparams, formals, restpe, argtpes, pt)
- checkBounds(fn.pos, NoPrefix, NoSymbol, okparams, okargs, "inferred ")
+ val AdjustedTypeArgs.AllArgsAndUndets(okparams, okargs, allargs, leftUndet) = methTypeArgs(undetparams, formals, restpe, argtpes, pt)
+ checkBounds(fn.pos, NoPrefix, NoSymbol, undetparams, allargs, "inferred ")
val treeSubst = new TreeTypeSubstituter(okparams, okargs)
treeSubst.traverse(fn)
treeSubst.traverseTrees(args)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index c0948a0752..7f68876327 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -299,7 +299,7 @@ trait Namers { self: Analyzer =>
val sym = tree.symbol
if (settings.debug.value) log("entered " + sym + " in " + context.owner + ", scope-id = " + context.scope.## )
var ltype = namerOf(sym).typeCompleter(tree)
- if (!tparams.isEmpty) {
+ if (tparams nonEmpty) {
//@M! TypeDef's type params are handled differently
//@M e.g., in [A[x <: B], B], A and B are entered first as both are in scope in the definition of x
//@M x is only in scope in `A[x <: B]'
@@ -376,8 +376,9 @@ trait Namers { self: Analyzer =>
name.endsWith(nme.OUTER, nme.OUTER.length) ||
context.unit.isJava) &&
!mods.isLazy) {
- tree.symbol = enterInScope(owner.newValue(tree.pos, name)
- .setFlag(mods.flags))
+ val vsym = owner.newValue(tree.pos, name).setFlag(mods.flags);
+ if(context.unit.isJava) setPrivateWithin(tree, vsym, mods) // #3663
+ tree.symbol = enterInScope(vsym)
finish
} else {
val mods1 =
@@ -420,7 +421,7 @@ trait Namers { self: Analyzer =>
addBeanGetterSetter(vd, getter)
}
case DefDef(mods, nme.CONSTRUCTOR, tparams, _, _, _) =>
- var sym = owner.newConstructor(tree.pos).setFlag(mods.flags | owner.getFlag(ConstrFlags))
+ val sym = owner.newConstructor(tree.pos).setFlag(mods.flags | owner.getFlag(ConstrFlags))
setPrivateWithin(tree, sym, mods)
tree.symbol = enterInScope(sym)
finishWith(tparams)
@@ -430,7 +431,7 @@ trait Namers { self: Analyzer =>
case TypeDef(mods, name, tparams, _) =>
var flags: Long = mods.flags
if ((flags & PARAM) != 0L) flags |= DEFERRED
- var sym = new TypeSymbol(owner, tree.pos, name).setFlag(flags)
+ val sym = new TypeSymbol(owner, tree.pos, name).setFlag(flags)
setPrivateWithin(tree, sym, mods)
tree.symbol = enterInScope(sym)
finishWith(tparams)
@@ -1070,23 +1071,17 @@ trait Namers { self: Analyzer =>
tp
}
- def verifyOverriding(other: Symbol): Boolean = {
- if(other.unsafeTypeParams.length != tparamSyms.length) {
- context.error(tpsym.pos,
- "The kind of "+tpsym.keyString+" "+tpsym.varianceString + tpsym.nameString+
- " does not conform to the expected kind of " + other.defString + other.locationString + ".")
- false
- } else true
- }
-
- // @M: make sure overriding in refinements respects rudimentary kinding
- // have to do this early, as otherwise we might get crashes: (see neg/bug1275.scala)
- // suppose some parameterized type member is overridden by a type member w/o params,
- // then appliedType will be called on a type that does not expect type args --> crash
- if (tpsym.owner.isRefinementClass && // only needed in refinements
- !tpsym.allOverriddenSymbols.forall{verifyOverriding(_)})
- ErrorType
- else polyType(tparamSyms, tp)
+ // see neg/bug1275, #3419
+ // used to do a rudimentary kind check here to ensure overriding in refinements
+ // doesn't change a type member's arity (number of type parameters),
+ // e.g. trait T { type X[A] }; type S = T{type X}; val x: S
+ // X in x.X[A] will get rebound to the X in the refinement, which does not take any type parameters
+ // this mismatch does not crash the compiler (anymore), but leads to weird type errors,
+ // as x.X[A] will become NoType internally
+ // it's not obvious the errror refers to the X in the refinement and not the original X
+ // however, separate compilation requires the symbol info to be loaded to do this check,
+ // but loading the info will probably lead to spurious cyclic errors --> omit the check
+ polyType(tparamSyms, tp)
}
/** Given a case class
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 18ccbecafc..74114b455e 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -421,8 +421,9 @@ abstract class RefChecks extends InfoTransform {
def javaErasedOverridingSym(sym: Symbol): Symbol =
clazz.tpe.nonPrivateMemberAdmitting(sym.name, BRIDGE).filter(other =>
!other.isDeferred && other.isJavaDefined && {
- val tp1 = erasure.erasure(clazz.thisType.memberType(sym))
- val tp2 = erasure.erasure(clazz.thisType.memberType(other))
+ def uncurryAndErase(tp: Type) = erasure.erasure(uncurry.transformInfo(sym, tp)) // #3622: erasure operates on uncurried types -- note on passing sym in both cases: only sym.isType is relevant for uncurry.transformInfo
+ val tp1 = uncurryAndErase(clazz.thisType.memberType(sym))
+ val tp2 = uncurryAndErase(clazz.thisType.memberType(other))
atPhase(currentRun.erasurePhase.next)(tp1 matches tp2)
})
@@ -1022,18 +1023,32 @@ abstract class RefChecks extends InfoTransform {
private def checkAnnotations(tpes: List[Type], pos: Position) = tpes foreach (tp => checkTypeRef(tp, pos))
private def doTypeTraversal(tree: Tree)(f: Type => Unit) = if (!inPattern) tree.tpe foreach f
- private def applyRefchecksToAnnotations(tree: Tree) = {
+ private def applyRefchecksToAnnotations(tree: Tree): Unit = {
def applyChecks(annots: List[AnnotationInfo]) = {
checkAnnotations(annots map (_.atp), tree.pos)
transformTrees(annots flatMap (_.args))
}
tree match {
- case m: MemberDef => applyChecks(m.symbol.annotations)
- case TypeTree() => doTypeTraversal(tree) {
- case AnnotatedType(annots, _, _) => applyChecks(annots)
- case _ =>
- }
+ case m: MemberDef =>
+ val sym = m.symbol
+ applyChecks(sym.annotations)
+ // validate implicitNotFoundMessage
+ analyzer.ImplicitNotFoundMsg.check(sym) foreach { warn =>
+ unit.warning(tree.pos, "Invalid implicitNotFound message for %s%s:\n%s".format(sym, sym.locationString, warn))
+ }
+ case tpt@TypeTree() =>
+ if(tpt.original != null) {
+ tpt.original foreach {
+ case dc@TypeTreeWithDeferredRefCheck() => applyRefchecksToAnnotations(dc.check()) // #2416
+ case _ =>
+ }
+ }
+
+ doTypeTraversal(tree) {
+ case AnnotatedType(annots, _, _) => applyChecks(annots)
+ case _ =>
+ }
case _ =>
}
}
@@ -1143,7 +1158,6 @@ abstract class RefChecks extends InfoTransform {
// type bounds (bug #935), issues deprecation warnings for symbols used
// inside annotations.
applyRefchecksToAnnotations(tree)
-
var result: Tree = tree match {
case DefDef(mods, name, tparams, vparams, tpt, EmptyTree) if tree.symbol.hasAnnotation(NativeAttr) =>
tree.symbol.resetFlag(DEFERRED)
@@ -1164,7 +1178,17 @@ abstract class RefChecks extends InfoTransform {
if (bridges.nonEmpty) treeCopy.Template(tree, parents, self, body ::: bridges)
else tree
- case TypeTree() =>
+ case dc@TypeTreeWithDeferredRefCheck() => assert(false, "adapt should have turned dc: TypeTreeWithDeferredRefCheck into tpt: TypeTree, with tpt.original == dc"); dc
+ case tpt@TypeTree() =>
+ if(tpt.original != null) {
+ tpt.original foreach {
+ case dc@TypeTreeWithDeferredRefCheck() =>
+ transform(dc.check()) // #2416 -- only call transform to do refchecks, but discard results
+ // tpt has the right type if the deferred checks are ok
+ case _ =>
+ }
+ }
+
val existentialParams = new ListBuffer[Symbol]
doTypeTraversal(tree) { // check all bounds, except those that are
// existential type parameters
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 12c4adb356..5fdf9267d2 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -191,6 +191,15 @@ trait Typers { self: Analyzer =>
argResultsBuff += inferImplicit(fun, paramTp, true, false, context)
}
+ def errorMessage(paramName: Name, paramTp: Type) =
+ paramTp.typeSymbol match {
+ case ImplicitNotFoundMsg(msg) => msg.format(paramName, paramTp)
+ case _ =>
+ "could not find implicit value for "+
+ (if (paramName startsWith nme.EVIDENCE_PARAM_PREFIX) "evidence parameter of type "
+ else "parameter "+paramName+": ")+paramTp
+ }
+
val argResults = argResultsBuff.toList
val args = argResults.zip(params) flatMap {
case (arg, param) =>
@@ -199,10 +208,7 @@ trait Typers { self: Analyzer =>
else List(atPos(arg.tree.pos)(new AssignOrNamedArg(Ident(param.name), (arg.tree))))
} else {
if (!param.hasFlag(DEFAULTPARAM))
- context.error(
- fun.pos, "could not find implicit value for "+
- (if (param.name startsWith nme.EVIDENCE_PARAM_PREFIX) "evidence parameter of type "
- else "parameter "+param.name+": ")+param.tpe)
+ context.error(fun.pos, errorMessage(param.name, param.tpe))
positional = false
Nil
}
@@ -555,6 +561,8 @@ trait Typers { self: Analyzer =>
* If symbol refers to package object, insert `.package` as second to last selector.
* (exception for some symbols in scala package which are dealiased immediately)
* Call checkAccessible, which sets tree's attributes.
+ * Also note that checkAccessible looks up sym on pre without checking that pre is well-formed
+ * (illegal type applications in pre will be skipped -- that's why typedSelect wraps the resulting tree in a TreeWithDeferredChecks)
* @return modified tree and new prefix type
*/
private def makeAccessible(tree: Tree, sym: Symbol, pre: Type, site: Tree): (Tree, Type) =
@@ -802,15 +810,10 @@ trait Typers { self: Analyzer =>
context.undetparams = context.undetparams ::: tparams1
adapt(tree1 setType restpe.substSym(tparams, tparams1), mode, pt, original)
case mt: MethodType if mt.isImplicit && ((mode & (EXPRmode | FUNmode | LHSmode)) == EXPRmode) => // (4.1)
- if (!context.undetparams.isEmpty/* && (mode & POLYmode) == 0 disabled to make implicits in new collection work; we should revisit this. */) { // (9)
- // println("adapt IMT: "+(context.undetparams, pt)) //@MDEBUG
- context.undetparams = inferExprInstance(
- tree, context.extractUndetparams(), pt, mt.params exists (p => isManifest(p.tpe)))
- // if we are looking for a manifest, instantiate type to Nothing anyway,
- // as we would get amnbiguity errors otherwise. Example
- // Looking for a manifest of Nil: This mas many potential types,
- // so we need to instantiate to minimal type List[Nothing].
- }
+ if (context.undetparams nonEmpty) // (9) -- should revisit dropped condition `(mode & POLYmode) == 0`
+ // dropped so that type args of implicit method are inferred even if polymorphic expressions are allowed
+ // needed for implicits in 2.8 collection library -- maybe once #3346 is fixed, we can reinstate the condition?
+ context.undetparams = inferExprInstance(tree, context.extractUndetparams(), pt, false) // false: retract Nothing's that indicate failure, ambiguities in manifests are dealt with in manifestOfType
val typer1 = constrTyperIf(treeInfo.isSelfOrSuperConstrCall(tree))
if (original != EmptyTree && pt != WildcardType)
typer1.silent(tpr => tpr.typed(tpr.applyImplicitArgs(tree), mode, pt)) match {
@@ -1776,8 +1779,18 @@ trait Typers { self: Analyzer =>
}
def typedTypeDef(tdef: TypeDef): TypeDef = {
- reenterTypeParams(tdef.tparams) // @M!
- val tparams1 = tdef.tparams mapConserve (typedTypeDef) // @M!
+ def typeDefTyper = {
+ if(tdef.tparams isEmpty) Typer.this
+ else newTyper(context.makeNewScope(tdef, tdef.symbol))
+ }
+ typeDefTyper.typedTypeDef0(tdef)
+ }
+
+ // call typedTypeDef instead
+ // a TypeDef with type parameters must always be type checked in a new scope
+ private def typedTypeDef0(tdef: TypeDef): TypeDef = {
+ reenterTypeParams(tdef.tparams)
+ val tparams1 = tdef.tparams mapConserve {typedTypeDef(_)}
val typedMods = removeAnnotations(tdef.mods)
// complete lazy annotations
val annots = tdef.symbol.annotations
@@ -2815,16 +2828,6 @@ trait Typers { self: Analyzer =>
res
}
- class SymInstance(val sym: Symbol, val tp: Type) {
- override def equals(other: Any): Boolean = other match {
- case that: SymInstance =>
- this.sym == that.sym && this.tp =:= that.tp
- case _ =>
- false
- }
- override def hashCode: Int = sym.hashCode * 41 + tp.hashCode
- }
-
/** convert skolems to existentials */
def packedType(tree: Tree, owner: Symbol): Type = {
def defines(tree: Tree, sym: Symbol) =
@@ -2860,7 +2863,7 @@ trait Typers { self: Analyzer =>
}
}
// add all local symbols of `tp' to `localSyms'
- // expanding higher-kinded types into individual copies for each instance.
+ // TODO: expand higher-kinded types into individual copies for each instance.
def addLocals(tp: Type) {
val remainingSyms = new ListBuffer[Symbol]
def addIfLocal(sym: Symbol, tp: Type) {
@@ -2969,6 +2972,11 @@ trait Typers { self: Analyzer =>
errorTree(tree, treeSymTypeMsg(fun)+" does not take type parameters.")
}
+ private[this] var typingIndent: String = ""
+ @inline final def deindentTyping() = if (printTypings) typingIndent = typingIndent.substring(0, typingIndent.length() - 2)
+ @inline final def indentTyping() = if (printTypings) typingIndent += " "
+ @inline final def printTyping(s: => String) = if (printTypings) println(typingIndent+s)
+
/**
* @param tree ...
* @param mode ...
@@ -3286,7 +3294,7 @@ trait Typers { self: Analyzer =>
def errorInResult(tree: Tree) = treesInResult(tree) exists (_.pos == ex.pos)
if (fun :: tree :: args exists errorInResult) {
- if (printTypings) println("second try for: "+fun+" and "+args)
+ printTyping("second try for: "+fun+" and "+args)
val Select(qual, name) = fun
val args1 = tryTypedArgs(args, argMode(fun, mode), ex)
val qual1 =
@@ -3296,9 +3304,8 @@ trait Typers { self: Analyzer =>
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)
- }
+ } else printTyping("no second try for "+fun+" and "+args+" because error not in result:"+ex.pos+"!="+tree.pos)
+
reportTypeError(tree.pos, ex)
setError(tree)
}
@@ -3537,9 +3544,9 @@ trait Typers { self: Analyzer =>
case Select(_, _) => treeCopy.Select(tree, qual, name)
case SelectFromTypeTree(_, _) => treeCopy.SelectFromTypeTree(tree, qual, name)
}
- //if (name.toString == "Elem") println("typedSelect "+qual+":"+qual.tpe+" "+sym+"/"+tree1+":"+tree1.tpe)
val (tree2, pre2) = makeAccessible(tree1, sym, qual.tpe, qual)
val result = stabilize(tree2, pre2, mode, pt)
+
def isPotentialNullDeference() = {
phase.id <= currentRun.typerPhase.id &&
!sym.isConstructor &&
@@ -3550,7 +3557,20 @@ trait Typers { self: Analyzer =>
if (settings.Xchecknull.value && isPotentialNullDeference && unit != null)
unit.warning(tree.pos, "potential null pointer dereference: "+tree)
- result
+ result match {
+ // could checkAccessible (called by makeAccessible) potentially have skipped checking a type application in qual?
+ case SelectFromTypeTree(qual@TypeTree(), name) if qual.tpe.typeArgs nonEmpty => // TODO: somehow the new qual is not checked in refchecks
+ treeCopy.SelectFromTypeTree(
+ result,
+ (TypeTreeWithDeferredRefCheck(){ () => val tp = qual.tpe; val sym = tp.typeSymbolDirect
+ // will execute during refchecks -- TODO: make private checkTypeRef in refchecks public and call that one?
+ checkBounds(qual.pos, tp.prefix, sym.owner, sym.typeParams, tp.typeArgs, "")
+ qual // you only get to see the wrapped tree after running this check :-p
+ }) setType qual.tpe,
+ name)
+ case _ =>
+ result
+ }
}
}
@@ -3683,6 +3703,7 @@ trait Typers { self: Analyzer =>
else atPos(tree.pos)(Select(qual, name))
// atPos necessary because qualifier might come from startContext
val (tree2, pre2) = makeAccessible(tree1, defSym, pre, qual)
+ // assert(pre.typeArgs isEmpty) // no need to add #2416-style check here, right?
stabilize(tree2, pre2, mode, pt)
}
}
@@ -3708,7 +3729,7 @@ trait Typers { self: Analyzer =>
} else {
val tparams = tpt1.symbol.typeParams
if (tparams.length == args.length) {
- // @M: kind-arity checking is done here and in adapt, full kind-checking is in checkKindBounds (in Infer)
+ // @M: kind-arity checking is done here and in adapt, full kind-checking is in checkKindBounds (in Infer)
val args1 =
if(!tpt1.symbol.rawInfo.isComplete)
args mapConserve (typedHigherKindedType(_, mode))
@@ -3719,11 +3740,8 @@ trait Typers { self: Analyzer =>
//@M! the polytype denotes the expected kind
}
val argtypes = args1 map (_.tpe)
- val owntype = if (tpt1.symbol.isClass || tpt1.symbol.isNonClassType)
- // @M! added the latter condition
- appliedType(tpt1.tpe, argtypes)
- else tpt1.tpe.instantiateTypeParams(tparams, argtypes)
- (args, tparams).zipped map { (arg, tparam) => arg match {
+
+ (args, tparams).zipped foreach { (arg, tparam) => arg match {
// note: can't use args1 in selector, because Bind's got replaced
case Bind(_, _) =>
if (arg.symbol.isAbstractType)
@@ -3733,7 +3751,17 @@ trait Typers { self: Analyzer =>
glb(List(arg.symbol.info.bounds.hi, tparam.info.bounds.hi.subst(tparams, argtypes))))
case _ =>
}}
- TypeTree(owntype) setOriginal(tree) // setPos tree.pos
+
+ val result = TypeTree(appliedType(tpt1.tpe, argtypes)) setOriginal(tree) // setPos tree.pos (done by setOriginal)
+ if(tpt1.tpe.isInstanceOf[PolyType]) // did the type application (performed by appliedType) involve an unchecked beta-reduction?
+ (TypeTreeWithDeferredRefCheck(){ () =>
+ // wrap the tree and include the bounds check -- refchecks will perform this check (that the beta reduction was indeed allowed) and unwrap
+ // we can't simply use original in refchecks because it does not contains types
+ // (and the only typed trees we have have been mangled so they're not quite the original tree anymore)
+ checkBounds(result.pos, tpt1.tpe.prefix, tpt1.symbol.owner, tpt1.symbol.typeParams, argtypes, "")
+ result // you only get to see the wrapped tree after running this check :-p
+ }).setType(result.tpe)
+ else result
} else if (tparams.length == 0) {
errorTree(tree, tpt1.tpe+" does not take type parameters")
} else {
@@ -3774,7 +3802,7 @@ trait Typers { self: Analyzer =>
newTyper(context.makeNewScope(tree, sym)).typedDefDef(ddef)
case tdef @ TypeDef(_, _, _, _) =>
- newTyper(context.makeNewScope(tree, sym)).typedTypeDef(tdef)
+ typedTypeDef(tdef)
case ldef @ LabelDef(_, _, _) =>
labelTyper(ldef).typedLabelDef(ldef)
@@ -4045,7 +4073,7 @@ trait Typers { self: Analyzer =>
case SelectFromTypeTree(qual, selector) =>
val qual1 = typedType(qual, mode)
if (qual1.tpe.isVolatile) error(tree.pos, "illegal type selection from volatile type "+qual.tpe)
- typedSelect(typedType(qual, mode), selector)
+ typedSelect(qual1, selector)
case CompoundTypeTree(templ) =>
typedCompoundTypeTree(templ)
@@ -4061,6 +4089,7 @@ trait Typers { self: Analyzer =>
case etpt @ ExistentialTypeTree(_, _) =>
newTyper(context.makeNewScope(tree, context.owner)).typedExistentialTypeTree(etpt, mode)
+ case dc@TypeTreeWithDeferredRefCheck() => dc // TODO: should we re-type the wrapped tree? then we need to change TypeTreeWithDeferredRefCheck's representation to include the wrapped tree explicitly (instead of in its closure)
case tpt @ TypeTree() =>
if (tpt.original != null)
tree setType typedType(tpt.original, mode).tpe
@@ -4083,8 +4112,7 @@ trait Typers { self: Analyzer =>
* @param pt ...
* @return ...
*/
- def typed(tree: Tree, mode: Int, pt: Type): Tree = {
-
+ def typed(tree: Tree, mode: Int, pt: Type): Tree = { indentTyping()
def dropExistential(tp: Type): Type = tp match {
case ExistentialType(tparams, tpe) =>
if (settings.debug.value) println("drop ex "+tree+" "+tp)
@@ -4110,15 +4138,15 @@ trait Typers { self: Analyzer =>
tree.tpe = null
if (tree.hasSymbol) tree.symbol = NoSymbol
}
- if (printTypings) println("typing "+tree+", pt = "+pt+", undetparams = "+context.undetparams+", implicits-enabled = "+context.implicitsEnabled+", silent = "+context.reportGeneralErrors) //DEBUG
+ printTyping("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+(if (isSingleType(tree1.tpe)) " with underlying "+tree1.tpe.widen else "")+", undetparams = "+context.undetparams+", pt = "+pt) //DEBUG
+ printTyping("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)
val result = if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt, tree)
- if (printTypings) println("adapted "+tree1+":"+tree1.tpe.widen+" to "+pt+", "+context.undetparams) //DEBUG
+ printTyping("adapted "+tree1+":"+tree1.tpe.widen+" to "+pt+", "+context.undetparams) //DEBUG
// for (t <- tree1.tpe) assert(t != WildcardType)
// if ((mode & TYPEmode) != 0) println("type: "+tree1+" has type "+tree1.tpe)
if (phase.id <= currentRun.typerPhase.id) signalDone(context.asInstanceOf[analyzer.Context], tree, result)
@@ -4126,7 +4154,7 @@ trait Typers { self: Analyzer =>
} catch {
case ex: TypeError =>
tree.tpe = null
- if (printTypings) println("caught "+ex+" in typed: "+tree) //DEBUG
+ printTyping("caught "+ex+" in typed: "+tree) //DEBUG
reportTypeError(tree.pos, ex)
setError(tree)
case ex: Exception =>
@@ -4138,6 +4166,7 @@ trait Typers { self: Analyzer =>
throw ex
}
finally {
+ deindentTyping()
if (Statistics.enabled) {
val t = currentTime()
microsByType(pendingTreeTypes.head) += ((t - typerTime) / 1000).toInt
diff --git a/src/library/scala/annotation/implicitNotFound.scala b/src/library/scala/annotation/implicitNotFound.scala
new file mode 100644
index 0000000000..5d9b29c5f8
--- /dev/null
+++ b/src/library/scala/annotation/implicitNotFound.scala
@@ -0,0 +1,18 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2010, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.annotation
+
+/**
+ * An annotation that specifies the error message that is emitted when the compiler
+ * cannot find an implicit value of the annotated type.
+ *
+ * @author Adriaan Moors
+ * @since 2.8.1
+ */
+final class implicitNotFound(msg: String) extends StaticAnnotation {} \ No newline at end of file
diff --git a/src/library/scala/collection/generic/CanBuildFrom.scala b/src/library/scala/collection/generic/CanBuildFrom.scala
index 79e352690e..4c923dca44 100644
--- a/src/library/scala/collection/generic/CanBuildFrom.scala
+++ b/src/library/scala/collection/generic/CanBuildFrom.scala
@@ -11,7 +11,7 @@ package scala.collection
package generic
import mutable.Builder
-
+import scala.annotation.implicitNotFound
/** A base trait for builder factories.
*
@@ -25,6 +25,7 @@ import mutable.Builder
* @author Adriaan Moors
* @since 2.8
*/
+@implicitNotFound(msg = "Cannot construct a collection of type ${To} with elements of type ${Elem} based on a collection of type ${To}.")
trait CanBuildFrom[-From, -Elem, +To] {
/** Creates a new builder on request of a collection.
diff --git a/test/files/neg/bug1275.check b/test/files/neg/bug1275.check
index 9f806c0689..6ee8365796 100644
--- a/test/files/neg/bug1275.check
+++ b/test/files/neg/bug1275.check
@@ -1,4 +1,6 @@
-bug1275.scala:13: error: The kind of type MyType does not conform to the expected kind of type MyType[+t] <: TestCovariance.Seq[t] in trait Seq.
- def span[a, s <: Seq[a] { type MyType <: s } ](xs: s): s = xs f
- ^
+bug1275.scala:11: error: type mismatch;
+ found : xs.MyType[a]
+ required: s
+ = xs f
+ ^
one error found
diff --git a/test/files/neg/bug1275.scala b/test/files/neg/bug1275.scala
index e9be13c763..1175b30763 100644
--- a/test/files/neg/bug1275.scala
+++ b/test/files/neg/bug1275.scala
@@ -1,14 +1,15 @@
-// tested using Scala compiler version 2.6.0-RC1 -- (c) 2002-2010 LAMP/EPFL
-
-// prompted by "Covariant return types" mailing list question
-object TestCovariance {
-
- // see Type constructor polymorphism in http://www.scala-lang.org/docu/changelog.html
- trait Seq[+t] {
- type MyType[+t] <: Seq[t]
-
- def f: MyType[t]
- }
-
- def span[a, s <: Seq[a] { type MyType <: s } ](xs: s): s = xs f
-}
+object Test {
+ trait Seq[+t] {
+ type MyType[+t] <: Seq[t]
+
+ def f: MyType[t]
+ }
+
+ // illegal abstract type member refinement: changes the arity of MyType
+ // the error is pretty strange, since the compiler forms the illegal type xs.MyType[a] anyway
+ def span[a, s <: Seq[a] { type MyType/*look ma, no type parameters!*/ <: s } ](xs: s): s
+ = xs f
+// ^
+// found : xs.MyType[a]
+// required: s
+} \ No newline at end of file
diff --git a/test/files/neg/bug882.check b/test/files/neg/bug882.check
index 8f47fefd9b..4e3e6d0860 100644
--- a/test/files/neg/bug882.check
+++ b/test/files/neg/bug882.check
@@ -1,4 +1,4 @@
-bug882.scala:2: error: traits cannot have type parameters with context bounds `: ...'
+bug882.scala:2: error: traits cannot have type parameters with context bounds `: ...' nor view bounds `<% ...'
trait SortedSet[A <% Ordered[A]] {
^
one error found
diff --git a/test/files/neg/t2416.check b/test/files/neg/t2416.check
new file mode 100644
index 0000000000..0899ad09d5
--- /dev/null
+++ b/test/files/neg/t2416.check
@@ -0,0 +1,10 @@
+t2416.scala:3: error: type arguments [Int] do not conform to trait A's type parameter bounds [X <: Double]
+ def x : A[Int]#B = 10 // no you won't
+ ^
+t2416.scala:8: error: type arguments [Boolean] do not conform to type B's type parameter bounds [Y <: Double]
+ def x : A#B[Boolean] = 10 // seriously?
+ ^
+t2416.scala:13: error: type arguments [String] do not conform to type B's type parameter bounds [Z <: Double]
+ type C[Z <: A] = Z#B[String] // nuh-uh!
+ ^
+three errors found
diff --git a/test/files/neg/t2416.scala b/test/files/neg/t2416.scala
new file mode 100644
index 0000000000..6bb57a984b
--- /dev/null
+++ b/test/files/neg/t2416.scala
@@ -0,0 +1,14 @@
+object t2416a {
+ trait A[X <: Double] { type B = X }
+ def x : A[Int]#B = 10 // no you won't
+}
+
+object t2416b {
+ trait A{type B[Y <: Double] = Int}
+ def x : A#B[Boolean] = 10 // seriously?
+}
+
+object t2416c {
+ trait A{type B[Z <: Double] = Int}
+ type C[Z <: A] = Z#B[String] // nuh-uh!
+} \ No newline at end of file
diff --git a/test/files/neg/t2462a.check b/test/files/neg/t2462a.check
new file mode 100644
index 0000000000..040a01f3a1
--- /dev/null
+++ b/test/files/neg/t2462a.check
@@ -0,0 +1,4 @@
+t2462a.scala:2: error: Cannot construct a collection of type List[String] with elements of type Int based on a collection of type List[String].
+ List(1,2,3).map[Int, List[String]](x => 1)
+ ^
+one error found
diff --git a/test/files/neg/t2462a.scala b/test/files/neg/t2462a.scala
new file mode 100644
index 0000000000..2d523b4dd8
--- /dev/null
+++ b/test/files/neg/t2462a.scala
@@ -0,0 +1,3 @@
+object Test {
+ List(1,2,3).map[Int, List[String]](x => 1)
+} \ No newline at end of file
diff --git a/test/files/neg/t2462b.check b/test/files/neg/t2462b.check
new file mode 100644
index 0000000000..bc0d9aa469
--- /dev/null
+++ b/test/files/neg/t2462b.check
@@ -0,0 +1,14 @@
+t2462b.scala:6: warning: Invalid implicitNotFound message for trait Meh in package test:
+The type parameters Too, Elem referenced in the message of the @implicitNotFound annotation are not defined by trait Meh.
+trait Meh[-From, +To]
+ ^
+t2462b.scala:9: warning: Invalid implicitNotFound message for trait Meh2 in package test:
+The type parameter Elem referenced in the message of the @implicitNotFound annotation is not defined by trait Meh2.
+trait Meh2[-From, +To]
+ ^
+t2462b.scala:12: error: overriding method x in class thankyoupartest of type => Int;
+ method x needs `override' modifier
+class testmustfail extends thankyoupartest { def x = 43 }
+ ^
+two warnings found
+one error found
diff --git a/test/files/neg/t2462b.scala b/test/files/neg/t2462b.scala
new file mode 100644
index 0000000000..7a1389cc8e
--- /dev/null
+++ b/test/files/neg/t2462b.scala
@@ -0,0 +1,12 @@
+package test
+
+import scala.annotation.implicitNotFound
+
+@implicitNotFound(msg = "Cannot construct a collection of type ${Too} with elements of type ${Elem} based on a collection of type ${From}.")
+trait Meh[-From, +To]
+
+@implicitNotFound(msg = "Cannot construct a collection of type ${To} ${Elem}.")
+trait Meh2[-From, +To]
+
+class thankyoupartest { def x = 42 }
+class testmustfail extends thankyoupartest { def x = 43 }
diff --git a/test/files/neg/t3399.check b/test/files/neg/t3399.check
new file mode 100644
index 0000000000..eb6c679704
--- /dev/null
+++ b/test/files/neg/t3399.check
@@ -0,0 +1,4 @@
+t3399.scala:23: error: could not find implicit value for parameter e: =:=[Nats.Add[Nats._1,Nats._1],Nats._1]
+ implicitly[ Add[_1, _1] =:= _1]
+ ^
+one error found
diff --git a/test/files/neg/t3399.scala b/test/files/neg/t3399.scala
new file mode 100644
index 0000000000..3edaa0724f
--- /dev/null
+++ b/test/files/neg/t3399.scala
@@ -0,0 +1,24 @@
+object Nats {
+ sealed trait Nat {
+ // fold right on N, N-1, ..., 1
+ type FoldR[Init <: Type, Type, F <: Fold[Nat, Type]] <: Type
+ }
+ sealed trait _0 extends Nat {
+ type FoldR[Init <: Type, Type, F <: Fold[Nat, Type]] = Init
+ }
+ sealed trait Succ[N <: Nat] extends Nat {
+ type FoldR[Init <: Type, Type, F <: Fold[Nat, Type]] =
+ F#Apply[Succ[N], N#FoldR[Init, Type, F]]
+ }
+
+ type Add[A <: Nat, B <: Nat] = A#FoldR[B, Nat, Inc]
+ trait Fold[-Elem, Value] {
+ type Apply[N <: Elem, Acc <: Value] <: Value
+ }
+ type Inc = Fold[Any, Nat] {
+ type Apply[N <: Any, Acc <: Nat] = Succ[Acc]
+ }
+
+ type _1 = Succ[_0]
+ implicitly[ Add[_1, _1] =:= _1]
+} \ No newline at end of file
diff --git a/test/files/neg/t3507.check b/test/files/neg/t3507.check
new file mode 100644
index 0000000000..1246a20d09
--- /dev/null
+++ b/test/files/neg/t3507.check
@@ -0,0 +1,4 @@
+t3507.scala:13: error: could not find implicit value for evidence parameter of type Manifest[object _1.b.c]
+ mani/*[object _1.b.c]*/(c) // kaboom in manifestOfType / TreeGen.mkAttributedQualifier
+ ^
+one error found
diff --git a/test/files/neg/t3507.scala b/test/files/neg/t3507.scala
new file mode 100644
index 0000000000..9a8c7c5462
--- /dev/null
+++ b/test/files/neg/t3507.scala
@@ -0,0 +1,15 @@
+class A {
+ object b {
+ object c
+ }
+ def m = b.c
+}
+
+object Test {
+ var a: A = new A // mutable
+ val c /*: object _1.b.c forSome { val _1: A } */ = a.m // widening using existential
+
+ def mani[T: Manifest](x: T) = ()
+ mani/*[object _1.b.c]*/(c) // kaboom in manifestOfType / TreeGen.mkAttributedQualifier
+ // --> _1 is not in scope here
+} \ No newline at end of file
diff --git a/test/files/neg/t3653.check b/test/files/neg/t3653.check
new file mode 100644
index 0000000000..ac6e2ca9dc
--- /dev/null
+++ b/test/files/neg/t3653.check
@@ -0,0 +1,7 @@
+t3653.scala:3: error: double definition:
+method x:(implicit x: Int)Int and
+method x:(i: Int)Int at line 2
+have same type after erasure: (x: Int)Int
+ def x(implicit x: Int) = 5
+ ^
+one error found
diff --git a/test/files/neg/t3653.scala b/test/files/neg/t3653.scala
new file mode 100644
index 0000000000..96cf96008a
--- /dev/null
+++ b/test/files/neg/t3653.scala
@@ -0,0 +1,4 @@
+class B {
+ def x(i: Int) = 3
+ def x(implicit x: Int) = 5
+} \ No newline at end of file
diff --git a/test/files/neg/t3663.check b/test/files/neg/t3663.check
new file mode 100644
index 0000000000..09ea25ad91
--- /dev/null
+++ b/test/files/neg/t3663.check
@@ -0,0 +1,4 @@
+main.scala:11: error: variable foo cannot be accessed in test.Test
+ println(t.foo)
+ ^
+one error found
diff --git a/test/files/neg/t3663/PackageProtected.java b/test/files/neg/t3663/PackageProtected.java
new file mode 100644
index 0000000000..f4535a55b4
--- /dev/null
+++ b/test/files/neg/t3663/PackageProtected.java
@@ -0,0 +1,5 @@
+package test;
+
+class PackageProtected {
+ int foo;
+}
diff --git a/test/files/neg/t3663/main.scala b/test/files/neg/t3663/main.scala
new file mode 100644
index 0000000000..29619550cc
--- /dev/null
+++ b/test/files/neg/t3663/main.scala
@@ -0,0 +1,14 @@
+package test
+
+final class Test extends PackageProtected {
+ def bar = foo
+}
+
+package another {
+ object Main {
+ def bug(t: Test) {
+ // Can always be replicated.
+ println(t.foo)
+ }
+ }
+} \ No newline at end of file
diff --git a/test/files/neg/t3691.check b/test/files/neg/t3691.check
new file mode 100644
index 0000000000..1b548cc84d
--- /dev/null
+++ b/test/files/neg/t3691.check
@@ -0,0 +1,16 @@
+t3691.scala:4: error: type mismatch;
+ found : java.lang.Object with Test.A[String]
+ required: AnyRef{type A[x]}
+ val b = (new A[String]{}): { type A[x] } // not ok
+ ^
+t3691.scala:5: error: type mismatch;
+ found : java.lang.Object with Test.A[String]
+ required: AnyRef{type A}
+ val c = (new A[String]{}): { type A } // not ok
+ ^
+t3691.scala:7: error: type mismatch;
+ found : java.lang.Object{type A = String}
+ required: AnyRef{type A[X]}
+ val x = (new { type A = String }): { type A[X] } // not ok
+ ^
+three errors found
diff --git a/test/files/neg/t3691.scala b/test/files/neg/t3691.scala
new file mode 100644
index 0000000000..69e8bef630
--- /dev/null
+++ b/test/files/neg/t3691.scala
@@ -0,0 +1,11 @@
+object Test {
+ trait A[X] { type A[x <: X] = x }
+ val a = (new A[String]{}): { type A[x <: String] } // ok
+ val b = (new A[String]{}): { type A[x] } // not ok
+ val c = (new A[String]{}): { type A } // not ok
+
+ val x = (new { type A = String }): { type A[X] } // not ok
+//a: AnyRef{type A[X]}
+
+ identity[x.A[Any]] _
+} \ No newline at end of file
diff --git a/test/files/neg/t742.check b/test/files/neg/t742.check
new file mode 100644
index 0000000000..f587948ef1
--- /dev/null
+++ b/test/files/neg/t742.check
@@ -0,0 +1,5 @@
+t742.scala:5: error: kinds of the type arguments (Crash._1,Crash._2,Any) do not conform to the expected kinds of the type parameters (type m,type n,type z).
+Crash._1's type parameters do not match type m's expected parameters: type s1 has one type parameter, but type n has two
+ type p = mul[_1, _2, Any] // mul[_1, _1, Any] needs -Yrecursion
+ ^
+one error found
diff --git a/test/files/neg/t742.scala b/test/files/neg/t742.scala
new file mode 100644
index 0000000000..bb1c2f85ea
--- /dev/null
+++ b/test/files/neg/t742.scala
@@ -0,0 +1,8 @@
+object Crash {
+ type mul[m[n[s[_], z], z], n[s[_], z], z] = m[n, z]
+ type _1[s1[_], z1] = s1[z1]
+ type _2[s1[_], z1] = s1[z1]
+ type p = mul[_1, _2, Any] // mul[_1, _1, Any] needs -Yrecursion
+ // _1[_2, Zero]
+ // _2[Zero]
+} \ No newline at end of file
diff --git a/test/files/pos/nothing_manifest_disambig.scala b/test/files/pos/nothing_manifest_disambig.scala
new file mode 100644
index 0000000000..9a3db0c6d4
--- /dev/null
+++ b/test/files/pos/nothing_manifest_disambig.scala
@@ -0,0 +1,10 @@
+object Test {
+ def mani[T: Manifest](xs: T) = xs
+ mani(List())
+
+ def listElMani[T: Manifest](xs: List[T]) = xs
+ listElMani(List())
+
+ def foo[A, C](m : C)(implicit ev: C <:< Traversable[A], mani: Manifest[A]): (C, A, Manifest[A]) = (m, m.head, mani)
+ foo(List(1,2,3))
+} \ No newline at end of file
diff --git a/test/files/pos/t2331.scala b/test/files/pos/t2331.scala
new file mode 100644
index 0000000000..9a15b5c2a9
--- /dev/null
+++ b/test/files/pos/t2331.scala
@@ -0,0 +1,11 @@
+trait C {
+ def m[T]: T
+}
+
+object Test {
+ val o /*: C --> no crash*/ = new C {
+ def m[T]: Nothing /*: T --> no crash*/ = error("omitted")
+ }
+
+ o.m[Nothing]
+} \ No newline at end of file
diff --git a/test/files/pos/t3249/Test.java b/test/files/pos/t3249/Test.java
new file mode 100644
index 0000000000..4cc7cb2ab5
--- /dev/null
+++ b/test/files/pos/t3249/Test.java
@@ -0,0 +1,5 @@
+public class Test {
+ public static void meh() {
+ new A<Integer>().f();
+ }
+} \ No newline at end of file
diff --git a/test/files/pos/t3249/a.scala b/test/files/pos/t3249/a.scala
new file mode 100644
index 0000000000..0394464549
--- /dev/null
+++ b/test/files/pos/t3249/a.scala
@@ -0,0 +1,11 @@
+class A[U] { def f[T] = { class X extends A[T] } }
+
+
+/*
+$ scalac a.scala
+$ javac -cp .:$SCALA_HOME/lib/scala-library.jar -Xprint 'A$X$1'
+
+ public class X$1 extends A<java.lang.Object> implements scala.ScalaObject {
+ public X$1(A<U> null);
+ }
+*/ \ No newline at end of file
diff --git a/test/files/pos/t3374.scala b/test/files/pos/t3374.scala
new file mode 100644
index 0000000000..4c0293181d
--- /dev/null
+++ b/test/files/pos/t3374.scala
@@ -0,0 +1,6 @@
+trait Parent {
+ type Test[A, H[B <: A]]
+}
+trait Sub extends Parent {
+ type Test[AS, HS[B <: AS]] = AS
+} \ No newline at end of file
diff --git a/test/files/pos/t3419/B_1.scala b/test/files/pos/t3419/B_1.scala
new file mode 100644
index 0000000000..a8ec7edba4
--- /dev/null
+++ b/test/files/pos/t3419/B_1.scala
@@ -0,0 +1,3 @@
+trait T[A,B] {
+ type X[a <: A, b <: B] <: B
+} \ No newline at end of file
diff --git a/test/files/pos/t3419/C_2.scala b/test/files/pos/t3419/C_2.scala
new file mode 100644
index 0000000000..da721d2c31
--- /dev/null
+++ b/test/files/pos/t3419/C_2.scala
@@ -0,0 +1,3 @@
+object F {
+ type S = T[Any,Int] {type X[N <: Int, Acc <: Int] = Acc}
+} \ No newline at end of file
diff --git a/test/files/pos/t3477.scala b/test/files/pos/t3477.scala
new file mode 100644
index 0000000000..660aa55736
--- /dev/null
+++ b/test/files/pos/t3477.scala
@@ -0,0 +1,7 @@
+class J3 {
+ def f[K, K1 >: K, V](x: Map[K1, V]): Map[K, V] = error("")
+}
+
+object Test {
+ (new J3).f(Map[Int, Int]())
+} \ No newline at end of file
diff --git a/test/files/pos/t3486/JTest.java b/test/files/pos/t3486/JTest.java
new file mode 100644
index 0000000000..0bf388b72d
--- /dev/null
+++ b/test/files/pos/t3486/JTest.java
@@ -0,0 +1,3 @@
+public class JTest<A> extends T2<A> {
+ public A m( A a ) { return a; }
+} \ No newline at end of file
diff --git a/test/files/pos/t3486/test.scala b/test/files/pos/t3486/test.scala
new file mode 100644
index 0000000000..544232b0d1
--- /dev/null
+++ b/test/files/pos/t3486/test.scala
@@ -0,0 +1,6 @@
+trait Test[A] {
+ def m( a: A ): A
+ def specified(a:A):A = a
+}
+
+abstract class T2[A] extends Test[A] \ No newline at end of file
diff --git a/test/files/pos/t3494.scala b/test/files/pos/t3494.scala
new file mode 100644
index 0000000000..35a4bcde5d
--- /dev/null
+++ b/test/files/pos/t3494.scala
@@ -0,0 +1,7 @@
+object Test {
+ def f[T](xs: T*) = ()
+
+ val x = "abc"
+
+ f[x.type](x)
+} \ No newline at end of file
diff --git a/test/files/pos/t3582.scala b/test/files/pos/t3582.scala
new file mode 100644
index 0000000000..0ac112efbf
--- /dev/null
+++ b/test/files/pos/t3582.scala
@@ -0,0 +1,12 @@
+trait C[A]
+object Test {
+ def ImplicitParamCA[CC[A], A](implicit ev: C[A]) {implicitly[C[A]]} // must use this exact syntax...
+ // error: could not find implicit value for parameter e: C[A]
+}
+// [[syntax trees at end of typer]]
+// abstract trait C#5[A#9116 >: Nothing#5832 <: Any#52] extends scala#33.AnyRef#2780;
+// final object Test#15 extends java.lang.Object#2485 with ScalaObject#1913 {
+// def ImplicitParamCA#9123[CC#9124[A#10858 >: Nothing#5832 <: Any#52] >: [A#10858]Nothing#5832 <: [A#10858]Any#52,
+// A#9125 >: Nothing#5832 <: Any#52](implicit ev#10856: C#5[A#9127]): Unit#3818
+// = scala#34.this.Predef#1683.implicitly#8816[C#5[A#10858]]()
+// }
diff --git a/test/files/pos/t3582b.scala b/test/files/pos/t3582b.scala
new file mode 100644
index 0000000000..8f0bfb9b2a
--- /dev/null
+++ b/test/files/pos/t3582b.scala
@@ -0,0 +1,5 @@
+object ParamScoping {
+ // scoping worked fine in the result type, but was wrong in body
+ // reason: typedTypeDef needs new context, which was set up by typed1 but not by typedDefDef and typedClassDef
+ def noOverlapFOwithHO[T, G[T]]: G[T] = null.asInstanceOf[G[T]]
+} \ No newline at end of file
diff --git a/test/files/pos/t3622/test/AsyncTask.java b/test/files/pos/t3622/test/AsyncTask.java
new file mode 100644
index 0000000000..cfcea3fe1a
--- /dev/null
+++ b/test/files/pos/t3622/test/AsyncTask.java
@@ -0,0 +1,5 @@
+package test;
+
+public abstract class AsyncTask<Params, Progress, Result> {
+ protected abstract Result doInBackground(Params... args);
+} \ No newline at end of file
diff --git a/test/files/pos/t3622/test/MyAsyncTask.java b/test/files/pos/t3622/test/MyAsyncTask.java
new file mode 100644
index 0000000000..9ef4947052
--- /dev/null
+++ b/test/files/pos/t3622/test/MyAsyncTask.java
@@ -0,0 +1,9 @@
+package test;
+
+public abstract class MyAsyncTask extends AsyncTask<String, String, String> {
+ protected abstract String doInBackground1(String[] args);
+ @Override
+ protected String doInBackground(String... args) {
+ return doInBackground1(new String[]{"dummy"});
+ }
+} \ No newline at end of file
diff --git a/test/files/pos/t3622/test/Test.scala b/test/files/pos/t3622/test/Test.scala
new file mode 100644
index 0000000000..fb82c581f9
--- /dev/null
+++ b/test/files/pos/t3622/test/Test.scala
@@ -0,0 +1,5 @@
+package test
+
+class Test extends MyAsyncTask {
+ protected[test] def doInBackground1(args: Array[String]): String = ""
+} \ No newline at end of file
diff --git a/test/files/pos/t3676.scala b/test/files/pos/t3676.scala
new file mode 100644
index 0000000000..60c0ceaec8
--- /dev/null
+++ b/test/files/pos/t3676.scala
@@ -0,0 +1,5 @@
+trait SeqLike[+Repr]
+trait Seq extends SeqLike[Seq]
+
+trait MySeq extends Seq with SeqLike[MySub]
+trait MySub extends MySeq
diff --git a/test/files/pos/t3777.scala b/test/files/pos/t3777.scala
new file mode 100644
index 0000000000..165eeebfdb
--- /dev/null
+++ b/test/files/pos/t3777.scala
@@ -0,0 +1,7 @@
+object Test {
+ type Point = Map[Symbol, String]
+ type Points = IndexedSeq[Point]
+
+ def makePoints2: Points = IndexedSeq[Point]()
+ val spoints2 = util.Random.shuffle(makePoints2)
+}