From 77c01a9baca66c1a5a099318d403dbedbe4feeeb Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 27 Jun 2011 17:16:01 +0000 Subject: Don't infer anonymous classes. possible, just far enough to avoid all kinds of undesirable consequences which accompany the preservation of too much type information. (The problems are akin to inferring the singleton type too freely.) // Example of code which did not compile, but now does class A class B[T <: A](cons: T) object C extends B(new A {}) Closes #4110, #3048. I already ran this by moors, so review by odersky. --- src/compiler/scala/reflect/internal/Types.scala | 12 ++++++------ src/compiler/scala/tools/nsc/typechecker/Infer.scala | 4 ++-- test/files/jvm/manifests.check | 2 +- test/files/pos/bug3048.scala | 8 ++++++++ test/files/run/bug4110.check | 2 ++ test/files/run/bug4110.scala | 11 +++++++++++ 6 files changed, 30 insertions(+), 9 deletions(-) create mode 100644 test/files/pos/bug3048.scala create mode 100644 test/files/run/bug4110.check create mode 100644 test/files/run/bug4110.scala diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 6152cd70f5..bc9eda760c 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -5134,6 +5134,12 @@ A type's typeSymbol should never be inspected directly. val rest = elimSuper(ts1 filter (t1 => !(t <:< t1))) if (rest exists (t1 => t1 <:< t)) rest else t :: rest } + def elimAnonymousClass(t: Type) = t match { + case TypeRef(pre, clazz, Nil) if clazz.isAnonymousClass => + clazz.classBound.asSeenFrom(pre, clazz.owner) + case _ => + t + } /** A collector that tests for existential types appearing at given variance in a type */ class ContainsVariantExistentialCollector(v: Int) extends TypeCollector(false) { @@ -5153,12 +5159,6 @@ A type's typeSymbol should never be inspected directly. /** Eliminate from list of types all elements which are a subtype * of some other element of the list. */ private def elimSub(ts: List[Type], depth: Int): List[Type] = { - def elimAnonymousClass(t: Type) = t match { - case TypeRef(pre, clazz, List()) if clazz.isAnonymousClass => - clazz.classBound.asSeenFrom(pre, clazz.owner) - case _ => - t - } def elimSub0(ts: List[Type]): List[Type] = ts match { case List() => List() case t :: ts1 => diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index b8dcadc090..2bf1d0035d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -1214,7 +1214,7 @@ trait Infer { * * @param fn fn: the function that needs to be instantiated. * @param undetparams the parameters that need to be determined - * @param args the actional argumments in the call. + * @param args the actual arguments supplied in the call. * @param pt the expected type of the function application * @return The type parameters that remain uninstantiated, * and that thus have not been substituted. @@ -1234,7 +1234,7 @@ trait Infer { try { val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0 val formals = formalTypes(params0 map (_.tpe), args.length) - val argtpes = actualTypes(args map (_.tpe.deconst), formals.length) + val argtpes = actualTypes(args map (x => elimAnonymousClass(x.tpe.deconst)), formals.length) val restpe = fn.tpe.resultType(argtpes) val AdjustedTypeArgs.AllArgsAndUndets(okparams, okargs, allargs, leftUndet) = diff --git a/test/files/jvm/manifests.check b/test/files/jvm/manifests.check index 3b8ca5b5b1..54f504b929 100644 --- a/test/files/jvm/manifests.check +++ b/test/files/jvm/manifests.check @@ -29,7 +29,7 @@ x=Foo, m=Foo[scala.collection.immutable.List[Int]] x=Foo, m=Foo[Foo[Int]] x=Foo, m=Foo[scala.collection.immutable.List[Foo[Int]]] -x=Test1$$anon$1, m=Test1$$anon$1 +x=Test1$$anon$1, m=Object with Bar[java.lang.String] ()=() true=true diff --git a/test/files/pos/bug3048.scala b/test/files/pos/bug3048.scala new file mode 100644 index 0000000000..dc056ecba2 --- /dev/null +++ b/test/files/pos/bug3048.scala @@ -0,0 +1,8 @@ +class B +object C extends B + +class F[T <: B](cons: => T) +class F2[T <: B](cons: => T) extends F(cons) + +object D extends F2(C) // works +object E extends F2(new B {}) diff --git a/test/files/run/bug4110.check b/test/files/run/bug4110.check new file mode 100644 index 0000000000..8b005989de --- /dev/null +++ b/test/files/run/bug4110.check @@ -0,0 +1,2 @@ +Object with Test$A with Test$B +Object with Test$A with Test$B diff --git a/test/files/run/bug4110.scala b/test/files/run/bug4110.scala new file mode 100644 index 0000000000..a42646ce52 --- /dev/null +++ b/test/files/run/bug4110.scala @@ -0,0 +1,11 @@ +object Test extends App { + def inferredType[T : Manifest](v : T) = println(manifest[T]) + + trait A + trait B + + inferredType(new A with B) + + val name = new A with B + inferredType(name) +} \ No newline at end of file -- cgit v1.2.3