From 7a5aaa9e23a98d60343cc0c4411b3fc395faa3ab Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Thu, 3 May 2012 11:09:13 +0200 Subject: SI-5703: normalize refined types more to improve Array[T] java-interop with T[], normalize Object with Object{} to Object fix #SI-5688 by flattening refined types in parents updated check files to reflect flattening of refined types and updated position for refined types --- src/compiler/scala/reflect/internal/Types.scala | 31 +++++++++++++++------- .../nsc/symtab/classfile/ClassfileParser.scala | 6 ++++- .../scala/tools/nsc/typechecker/Namers.scala | 5 ++++ .../tools/nsc/typechecker/PatternMatching.scala | 2 +- 4 files changed, 33 insertions(+), 11 deletions(-) (limited to 'src/compiler/scala') diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 165f8119ce..799671f9e3 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -1610,12 +1610,26 @@ trait Types extends api.Types { self: SymbolTable => override def typeConstructor = copyRefinedType(this, parents map (_.typeConstructor), decls) - /* MO to AM: This is probably not correct - * If they are several higher-kinded parents with different bounds we need - * to take the intersection of their bounds - */ - override def normalize = { - if (isHigherKinded) { + final override def normalize: Type = + if (phase.erasedTypes) normalizeImpl + else { + if (normalized eq null) normalized = normalizeImpl + normalized + } + + private var normalized: Type = _ + private def normalizeImpl = { + // TODO see comments around def intersectionType and def merge + def flatten(tps: List[Type]): List[Type] = tps flatMap { case RefinedType(parents, ds) if ds.isEmpty => flatten(parents) case tp => List(tp) } + val flattened = flatten(parents).distinct + if (decls.isEmpty && flattened.tail.isEmpty) { + flattened.head + } else if (flattened != parents) { + refinedType(flattened, if (typeSymbol eq NoSymbol) NoSymbol else typeSymbol.owner, decls, NoPosition) + } else if (isHigherKinded) { + // MO to AM: This is probably not correct + // If they are several higher-kinded parents with different bounds we need + // to take the intersection of their bounds typeFun( typeParams, RefinedType( @@ -1625,8 +1639,7 @@ trait Types extends api.Types { self: SymbolTable => }, decls, typeSymbol)) - } - else super.normalize + } else super.normalize } /** A refined type P1 with ... with Pn { decls } is volatile if @@ -3322,7 +3335,7 @@ trait Types extends api.Types { self: SymbolTable => if (phase.erasedTypes) if (parents.isEmpty) ObjectClass.tpe else parents.head else { - val clazz = owner.newRefinementClass(NoPosition) + val clazz = owner.newRefinementClass(pos) // TODO: why were we passing in NoPosition instead of pos? val result = RefinedType(parents, decls, clazz) clazz.setInfo(result) result diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index b51c8baa31..739060d02e 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -774,8 +774,12 @@ abstract class ClassfileParser { // make unbounded Array[T] where T is a type variable into Array[T with Object] // (this is necessary because such arrays have a representation which is incompatible // with arrays of primitive types. - if (elemtp.typeSymbol.isAbstractType && !(elemtp <:< definitions.ObjectClass.tpe)) + // NOTE that the comparison to Object only works for abstract types bounded by classes that are strict subclasses of Object + // if the bound is exactly Object, it will have been converted to Any, and the comparison will fail + // see also RestrictJavaArraysMap (when compiling java sources directly) + if (elemtp.typeSymbol.isAbstractType && !(elemtp <:< definitions.ObjectClass.tpe)) { elemtp = intersectionType(List(elemtp, definitions.ObjectClass.tpe)) + } definitions.arrayType(elemtp) case '(' => diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 45f7d7e618..4e7dac890b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -1347,6 +1347,11 @@ trait Namers extends MethodSynthesis { /** Convert Java generic array type T[] to (T with Object)[] * (this is necessary because such arrays have a representation which is incompatible * with arrays of primitive types.) + * + * @note the comparison to Object only works for abstract types bounded by classes that are strict subclasses of Object + * if the bound is exactly Object, it will have been converted to Any, and the comparison will fail + * + * see also sigToType */ private object RestrictJavaArraysMap extends TypeMap { def apply(tp: Type): Type = tp match { diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala index c3a7f2bbc5..61e02edaff 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala @@ -931,7 +931,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL // implements the run-time aspects of (ยง8.2) (typedPattern has already done the necessary type transformations) // TODO: normalize construction, which yields a combination of a EqualityTestTreeMaker (when necessary) and a TypeTestTreeMaker case class TypeAndEqualityTestTreeMaker(prevBinder: Symbol, patBinder: Symbol, pt: Type, pos: Position) extends CondTreeMaker { - val nextBinderTp = glb(List(patBinder.info.widen, pt)) + val nextBinderTp = glb(List(patBinder.info.widen, pt)).normalize /** Type patterns consist of types, type variables, and wildcards. A type pattern T is of one of the following forms: - A reference to a class C, p.C, or T#C. -- cgit v1.2.3