From a7f68ce32c35c73af855eab26635251249ac171a Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sun, 1 Apr 2012 08:40:39 -0700 Subject: Unify "object Foo" and "Foo.type". The source of many bugs over the years is that the first is represented as a TypeRef and the second a SingleType. Over a great period of time I figured out how to shield us from the more obvious bug manifestations, but a recent comment by adriaan jarred me into realizing that we can fix it at the source. This commit changes <:< and =:= to recognize when those two representations are being compared and to treat them as equivalent regardless of which is on the left. The reason I don't quash one representation entirely is that a fair bit of code depends on singleton types having an underlying type which is not the same, and regardless of that it would entail more changes and more risk. The change allows removing the type inference conditions which worried about this, and also fixes SI-4910. scala> val t1 = typeRef(ScalaPackageClass.thisType, NoneModule.moduleClass, Nil) t1: $r.intp.global.Type = None.type scala> val t2 = t1.narrow t2: $r.intp.global.Type = None.type scala> (t1.getClass, t2.getClass) res20: (Class[?0], Class[?0]) forSome { type ?0 <: $r.intp.global.Type; type ?0 <: $r.intp.global.Type } = (class scala.reflect.internal.Types$ModuleTypeRef,class scala.reflect.internal.Types$UniqueSingleType) scala> ((t1 =:= t2, t2 =:= t1, t1 <:< t2, t2 <:< t1)) res21: (Boolean, Boolean, Boolean, Boolean) = (true,true,true,true) --- src/compiler/scala/reflect/internal/Types.scala | 10 +++++++--- src/compiler/scala/tools/nsc/typechecker/Infer.scala | 3 +-- src/compiler/scala/tools/nsc/typechecker/Namers.scala | 5 +---- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 5afa5343ed..786b680ff8 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -5059,6 +5059,8 @@ trait Types extends api.Types { self: SymbolTable => case (_, tv @ TypeVar(_,_)) => tv.registerTypeSelection(tr2.sym, tr1) case _ => false }) + case _: SingleType => + return isSameType2(tp2, tp1) // put singleton type on the left, caught below case _ => } case tt1: ThisType => @@ -5071,6 +5073,8 @@ trait Types extends api.Types { self: SymbolTable => tp2 match { case st2: SingleType => if (equalSymsAndPrefixes(st1.sym, st1.pre, st2.sym, st2.pre)) return true + case TypeRef(pre2, sym2, Nil) => + if (sym2.isModuleClass && equalSymsAndPrefixes(st1.sym, st1.pre, sym2.sourceModule, pre2)) return true case _ => } case ct1: ConstantType => @@ -5481,7 +5485,7 @@ trait Types extends api.Types { self: SymbolTable => * - handle typerefs, refined types, notnull and singleton types. */ def fourthTry = tp1 match { - case tr1 @ TypeRef(_, sym1, _) => + case tr1 @ TypeRef(pre1, sym1, _) => sym1 match { case NothingClass => true case NullClass => @@ -5495,8 +5499,8 @@ trait Types extends api.Types { self: SymbolTable => if (isRaw(sym1, tr1.args)) isSubType(rawToExistential(tp1), tp2, depth) else if (sym1.isModuleClass) tp2 match { - case SingleType(_, sym2) => sym1 == sym2 - case _ => false + case SingleType(pre2, sym2) => equalSymsAndPrefixes(sym1.sourceModule, pre1, sym2, pre2) + case _ => false } else if (sym1.isRefinementClass) isSubType(sym1.info, tp2, depth) diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index a1ca4904f4..dba31f7bca 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -484,8 +484,7 @@ trait Infer { else Some( if (targ.typeSymbol == RepeatedParamClass) targ.baseType(SeqClass) else if (targ.typeSymbol == JavaRepeatedParamClass) targ.baseType(ArrayClass) - // this infers Foo.type instead of "object Foo" (see also widenIfNecessary) - else if (targ.typeSymbol.isModuleClass || ((opt.experimental || opt.virtPatmat) && tvar.constr.avoidWiden)) targ + else if ((opt.experimental || opt.virtPatmat) && tvar.constr.avoidWiden) targ else targ.widen ) )) diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 8604366bf2..1b505d1e5d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -793,10 +793,7 @@ trait Namers extends MethodSynthesis { val tpe1 = dropRepeatedParamType(tpe.deconst) val tpe2 = tpe1.widen - // This infers Foo.type instead of "object Foo" - // See Infer#adjustTypeArgs for the polymorphic case. - if (tpe.typeSymbolDirect.isModuleClass) tpe1 - else if (sym.isVariable || sym.isMethod && !sym.hasAccessorFlag) + if (sym.isVariable || sym.isMethod && !sym.hasAccessorFlag) if (tpe2 <:< pt) tpe2 else tpe1 else if (isHidden(tpe)) tpe2 // In an attempt to make pattern matches involving method local vals -- cgit v1.2.3