diff options
author | Paul Phillips <paulp@improving.org> | 2013-03-10 10:00:54 -0700 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2013-03-10 21:04:19 -0700 |
commit | 2fa2db784075dfb58cf507c45a948819ade8a6d4 (patch) | |
tree | 0e32232e8fa2ed376a51cd83efa12772c55c3721 | |
parent | 1b6297f642877dcc7edcd704a5d3cf99a12e54b8 (diff) | |
download | scala-2fa2db784075dfb58cf507c45a948819ade8a6d4.tar.gz scala-2fa2db784075dfb58cf507c45a948819ade8a6d4.tar.bz2 scala-2fa2db784075dfb58cf507c45a948819ade8a6d4.zip |
SI-7228, bug in weak subtyping.
Another in the category of bugs which involve narrowing,
widening, mediuming, dealiasing, weakening, normalizing,
denormalizing, supernormalizing, subnormalizing, and
double-bounded supersubnormalizing.
This is probably not the ideal fix, but it is an improvement.
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Implicits.scala | 23 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 2 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Types.scala | 4 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/tpe/TypeComparers.scala | 6 | ||||
-rw-r--r-- | test/files/pos/t7228.scala | 75 |
5 files changed, 91 insertions, 19 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 2331f82a58..29d4c8423b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -268,7 +268,7 @@ trait Implicits { */ object Function1 { val Sym = FunctionClass(1) - def unapply(tp: Type) = tp match { + def unapply(tp: Type) = tp baseType Sym match { case TypeRef(_, Sym, arg1 :: arg2 :: _) => Some((arg1, arg2)) case _ => None } @@ -431,10 +431,8 @@ trait Implicits { val start = if (Statistics.canEnable) Statistics.startTimer(matchesPtNanos) else null val result = normSubType(tp, pt) || isView && { pt match { - case TypeRef(_, Function1.Sym, arg1 :: arg2 :: Nil) => - matchesPtView(tp, arg1, arg2, undet) - case _ => - false + case Function1(arg1, arg2) => matchesPtView(tp, arg1, arg2, undet) + case _ => false } } if (Statistics.canEnable) Statistics.stopTimer(matchesPtNanos, start) @@ -576,20 +574,19 @@ trait Implicits { def fail(reason: String): SearchResult = failure(itree, reason) try { - val itree1 = - if (isView) { - val arg1 :: arg2 :: _ = pt.typeArgs + val itree1 = pt match { + case Function1(arg1, arg2) if isView => typed1( atPos(itree.pos)(Apply(itree, List(Ident("<argument>") setType approximate(arg1)))), EXPRmode, approximate(arg2) ) - } - else - typed1(itree, EXPRmode, wildPt) - - if (context.hasErrors) + case _ => typed1(itree, EXPRmode, wildPt) + } + if (context.hasErrors) { + log("implicit adapt failed: " + context.errBuffer.head.errMsg) return fail(context.errBuffer.head.errMsg) + } if (Statistics.canEnable) Statistics.incCounter(typedImplicits) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index eaf57cd39c..a110d6d15d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1133,7 +1133,7 @@ trait Typers extends Adaptations with Tags { return typedPos(tree.pos, mode, pt) { Block(List(tree), Literal(Constant())) } - } else if (isNumericValueClass(sym) && isNumericSubType(tree.tpe, pt)) { + } else if (isNumericValueClass(sym) && isNumericSubType(tree.tpe.dealiasWiden, pt)) { if (settings.warnNumericWiden.value) context.unit.warning(tree.pos, "implicit numeric widening") return typedPos(tree.pos, mode, pt) { diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index a6c5367425..b59732e595 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -1217,7 +1217,7 @@ trait Types protected def rewrap(newtp: Type): Type = NotNullType(newtp) override def isNotNull: Boolean = true override def notNull = this - override def deconst: Type = underlying //todo: needed? + override def deconst: Type = underlying.deconst //todo: needed? override def safeToString: String = underlying.toString + " with NotNull" override def kind = "NotNullType" } @@ -1989,7 +1989,7 @@ trait Types assert(underlying.typeSymbol != UnitClass) override def isTrivial: Boolean = true override def isNotNull = value.value != null - override def deconst: Type = underlying + override def deconst: Type = underlying.deconst override def safeToString: String = underlying.toString + "(" + value.escapedStringValue + ")" override def kind = "ConstantType" diff --git a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala index 82321f61c2..2d499cf299 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala @@ -583,7 +583,7 @@ trait TypeComparers { def isWeakSubType(tp1: Type, tp2: Type) = - tp1.deconst.normalize match { + tp1.widen.normalize match { case TypeRef(_, sym1, _) if isNumericValueClass(sym1) => tp2.deconst.normalize match { case TypeRef(_, sym2, _) if isNumericValueClass(sym2) => @@ -609,8 +609,8 @@ trait TypeComparers { * (Even if the calls are to typeSymbolDirect.) */ def isNumericSubType(tp1: Type, tp2: Type): Boolean = ( - isNumericValueType(tp1) - && isNumericValueType(tp2) + isNumericValueType(tp1.dealiasWiden) + && isNumericValueType(tp2.dealias) && isNumericSubClass(tp1.typeSymbol, tp2.typeSymbol) ) diff --git a/test/files/pos/t7228.scala b/test/files/pos/t7228.scala new file mode 100644 index 0000000000..5d936f6529 --- /dev/null +++ b/test/files/pos/t7228.scala @@ -0,0 +1,75 @@ +object AdaptWithWeaklyConformantType { + implicit class D(d: Double) { def double = d*2 } + + val x1: Int = 1 + var x2: Int = 2 + val x3 = 3 + var x4 = 4 + final val x5 = 5 + final var x6 = 6 + + def f1 = x1.double + def f2 = x2.double + def f3 = x3.double + def f4 = x4.double + def f5 = x5.double + def f6 = x6.double +} + +object AdaptAliasWithWeaklyConformantType { + implicit class D(d: Double) { def double = d*2 } + type T = Int + + val x1: T = 1 + var x2: T = 2 + val x3 = (3: T) + var x4 = (4: T) + final val x5 = (5: T) + final var x6 = (6: T) + + def f1 = x1.double + def f2 = x2.double + def f3 = x3.double + def f4 = x4.double + def f5 = x5.double + def f6 = x6.double +} + +object AdaptToAliasWithWeaklyConformantType { + type U = Double + implicit class D(d: U) { def double = d*2 } + + val x1: Int = 1 + var x2: Int = 2 + val x3 = (3: Int) + var x4 = (4: Int) + final val x5 = (5: Int) + final var x6 = (6: Int) + + def f1 = x1.double + def f2 = x2.double + def f3 = x3.double + def f4 = x4.double + def f5 = x5.double + def f6 = x6.double +} + +object AdaptAliasToAliasWithWeaklyConformantType { + type U = Double + type T = Int + implicit class D(d: U) { def double = d*2 } + + val x1: T = 1 + var x2: T = 2 + val x3 = (3: T) + var x4 = (4: T) + final val x5 = (5: T) + final var x6 = (6: T) + + def f1 = x1.double + def f2 = x2.double + def f3 = x3.double + def f4 = x4.double + def f5 = x5.double + def f6 = x6.double +} |