summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala12
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala24
-rw-r--r--test/files/neg/bug692.check7
-rw-r--r--test/files/pos/ticket2201.scala8
4 files changed, 41 insertions, 10 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index 707137dd78..5705399428 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -1410,15 +1410,11 @@ trait Types {
sym.isModuleClass || sym == NothingClass || isValueClass(sym) || super.isNotNull
// @M: propagate actual type params (args) to `tp', by replacing formal type parameters with actual ones
+ // if tp is higher kinded, the "actual" type arguments are types that simply reference the corresponding type parameters (unbound type variables)
def transform(tp: Type): Type = {
- val args = typeArgsOrDummies
- if (args.length == sym.typeParams.length)
- tp.asSeenFrom(pre, sym.owner).instantiateTypeParams(sym.typeParams, args)
- else {
- assert(sym.typeParams.isEmpty || (args exists (_.isError)) || isRaw(sym, args)/*#2266/2305*/, tp)
- tp
- }
- // @M TODO maybe we shouldn't instantiate type params if isHigherKinded -- probably needed for partial type application though
+ val res = tp.asSeenFrom(pre, sym.owner)
+ if (sym.typeParams.isEmpty || (args exists (_.isError)) || isRaw(sym, args)/*#2266/2305*/) res
+ else res.instantiateTypeParams(sym.typeParams, typeArgsOrDummies)
}
//@M! use appliedType on the polytype that represents the bounds (or if aliastype, the rhs)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 7ebaa27872..96670ab131 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -671,6 +671,28 @@ self: Analyzer =>
}
}
+ /** Construct a fresh symbol tree for an implicit parameter
+ because of caching, must clone symbols that represent bound variables,
+ or we will end up with different bound variables that are represented by the same symbol */
+ def freshenFunctionParameters(tree : Tree) : Tree = new Transformer {
+ currentOwner = context.owner
+ override val treeCopy = new LazyTreeCopier
+ override def transform(tr : Tree) = super.transform(tr match {
+ case Function(vparams, body) => {
+ // New tree
+ val sym = tr.symbol cloneSymbol currentOwner
+ val res = tr.duplicate setSymbol sym
+ // New parameter symbols
+ var oldsyms = vparams map (_.symbol)
+ var newsyms = cloneSymbols(oldsyms, sym)
+ // Fix all symbols
+ new TreeSymSubstituter(oldsyms, newsyms) traverse res
+ res
+ }
+ case x => x
+ })
+ } transform tree
+
/** Return cached search result if found. Otherwise update cache
* but keep within sizeLimit entries
*/
@@ -679,7 +701,7 @@ self: Analyzer =>
hits += 1
if (sr == SearchFailure) sr
else {
- val result = new SearchResult(sr.tree.duplicate, sr.subst)
+ val result = new SearchResult(freshenFunctionParameters(sr.tree.duplicate), sr.subst) // #2201: generate fresh symbols for parameters
for (t <- result.tree) t.setPos(tree.pos.focus)
result
}
diff --git a/test/files/neg/bug692.check b/test/files/neg/bug692.check
index 14df1917d9..9e96027899 100644
--- a/test/files/neg/bug692.check
+++ b/test/files/neg/bug692.check
@@ -13,7 +13,12 @@ bug692.scala:13: error: class Foo takes type parameters
bug692.scala:14: error: class Foo takes type parameters
implicit def typeOfBar[T4 <: Foo](implicit elem : RefType[T4]) : RefType[Bar[T4]] =
^
+bug692.scala:15: error: type mismatch;
+ found : test3.this.BarType[T4]
+ required: test3.this.RefType[test3.this.Bar[T4]]
+ BarType(elem);
+ ^
bug692.scala:19: error: class Foo takes type parameters
class Bar[A <: Foo](implicit tpeA : Type[A]) extends Foo;
^
-6 errors found
+7 errors found
diff --git a/test/files/pos/ticket2201.scala b/test/files/pos/ticket2201.scala
new file mode 100644
index 0000000000..275867b88e
--- /dev/null
+++ b/test/files/pos/ticket2201.scala
@@ -0,0 +1,8 @@
+class Test
+object Test { implicit def view(x : Test) = 0 }
+
+object Call {
+ def call(implicit view : Test => Int) = view(null)
+ call
+ call
+} \ No newline at end of file