diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Types.scala | 12 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Implicits.scala | 24 | ||||
-rw-r--r-- | test/files/neg/bug692.check | 7 | ||||
-rw-r--r-- | test/files/pos/ticket2201.scala | 8 |
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 |