Permalink
Browse files

Backport of SI-6846.

Squashed commit of the following:

commit 55806cc0e6177820c12a35a18b4f2a12dc07bb39
Author: Paul Phillips <paulp@improving.org>
Date:   Wed Dec 19 07:32:19 2012 -0800

    SI-6846, regression in type constructor inference.

    In 658ba1b some inference was gained and some was lost.
    In this commit we regain what was lost and gain even more.
    Dealiasing and widening should be fully handled now, as
    illustrated by the test case.
    (cherry picked from commit dbebcd5)

commit e6ef58447d0f4ef6de956fcc03ee283bb9028c02
Author: Paul Phillips <paulp@improving.org>
Date:   Fri Dec 21 15:11:29 2012 -0800

    Cleaning up type alias usage.

    I determined that many if not most of the calls to .normalize
    have no intent beyond dealiasing the type. In light of this I
    went call site to call site knocking on doors and asking why
    exactly they were calling any of

      .normalize
      .widen.normalize
      .normalize.widen

    and if I didn't like their answers they found themselves
    introduced to 'dropAliasesAndSingleTypes', the recursive widener
    and dealiaser which I concluded is necessary after all.

    Discovered that the object called 'deAlias' actually depends
    upon calling 'normalize', not 'dealias'. Decided this was
    sufficient cause to rename it to 'normalizeAliases'.

    Created dealiasWiden and dealiasWidenChain.

    Dropped dropAliasesAndSingleTypes in favor of methods
    on Type alongside dealias and widen (Type#dealiasWiden).
    These should reduce the number of "hey, the type alias doesn't work" bugs.

    (cherry picked from commit 3bf5118)

    Conflicts:
    	src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala

commit c1d8803cea1523f458730103386d8e14324a9446
Author: Paul Phillips <paulp@improving.org>
Date:   Sat Dec 22 08:13:48 2012 -0800

    Shored up a hidden dealiasing dependency.

    Like the comment says:

    // This way typedNew always returns a dealiased type. This
    // used to happen by accident for instantiations without type
    // arguments due to ad hoc code in typedTypeConstructor, and
    // annotations depended on it (to the extent that they worked,
    // which they did not when given a parameterized type alias
    // which dealiased to an annotation.) typedTypeConstructor
    // dealiases nothing now, but it makes sense for a "new" to
    // always be given a dealiased type.

    PS:
    Simply running the test suite is becoming more difficult all
    the time. Running "ant test" includes time consuming activities
    of niche interest such as all the osgi tests, but test.suite
    manages to miss the continuations tests.
    (cherry picked from commit 422f461)

commit da4748502792b260161baa10939554564c488051
Author: Paul Phillips <paulp@improving.org>
Date:   Fri Dec 21 12:39:02 2012 -0800

    Fix and simplify typedTypeConstructor.

    Investigating the useful output of devWarning (-Xdev people,
    it's good for you) led back to this comment:

      "normalize to get rid of type aliases"

    You may know that this is not all the normalizing does.
    Normalizing also turns TypeRefs with unapplied arguments
    (type constructors) into PolyTypes. That means that when
    typedParentType would call typedTypeConstructor it would
    find its parent had morphed into a PolyType. Not that it
    noticed; it would blithely continue and unwittingly discard
    the type arguments by way of appliedType (which smoothly
    logged the incident, thank you appliedType.)

    The simplification of typedTypeConstructor:

    There was a whole complicated special treatment of AnyRef
    here which appears to have become unnecessary. Removed special
    treatment and lit a candle for regularity.

    Updated lots of tests regarding newly not-so-special AnyRef.
    (cherry picked from commit 394cc42)

commit 1f3c77bacb2fbb3ba9e4ad0a8a733e0f9263b234
Author: Paul Phillips <paulp@improving.org>
Date:   Fri Dec 21 15:06:10 2012 -0800

    Removed dead implementation.

    Another "attractive nuisance" burning off time until I
    realized it was commented out.
    (cherry picked from commit ed40f5c)
  • Loading branch information...
1 parent 1381cda commit e5da30b843fe8bfe1638e3e08cdeaa4b6ae2f2d1 @retronym retronym committed Jan 8, 2013
Showing with 248 additions and 270 deletions.
  1. +5 −5 src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala
  2. +1 −1 src/compiler/scala/tools/nsc/interpreter/IMain.scala
  3. +14 −99 src/compiler/scala/tools/nsc/typechecker/Implicits.scala
  4. +7 −5 src/compiler/scala/tools/nsc/typechecker/Infer.scala
  5. +25 −30 src/compiler/scala/tools/nsc/typechecker/Typers.scala
  6. +40 −20 src/reflect/scala/reflect/internal/Types.scala
  7. +1 −1 test/files/continuations-neg/function2.check
  8. +2 −2 test/files/continuations-neg/t5314-type-error.check
  9. +12 −0 test/files/jvm/annotations.check
  10. +6 −0 test/files/jvm/annotations.scala
  11. +2 −2 test/files/neg/override-object-no.check
  12. +1 −1 test/files/neg/t2078.check
  13. +1 −1 test/files/neg/t2336.check
  14. +1 −1 test/files/neg/t3691.check
  15. +3 −3 test/files/neg/t4877.check
  16. +2 −2 test/files/neg/t5060.check
  17. +1 −1 test/files/neg/t5063.check
  18. +2 −2 test/files/neg/t6436.check
  19. +2 −2 test/files/neg/t6436b.check
  20. +1 −1 test/files/neg/t963.check
  21. +28 −0 test/files/pos/t6846.scala
  22. +52 −52 test/files/run/existentials-in-compiler.check
  23. +2 −2 test/files/run/existentials3-new.check
  24. +2 −2 test/files/run/existentials3-old.check
  25. +1 −1 test/files/run/macro-declared-in-trait.check
  26. +1 −1 test/files/run/reflection-equality.check
  27. +4 −4 test/files/run/repl-colon-type.check
  28. +1 −1 test/files/run/repl-parens.check
  29. +1 −1 test/files/run/t4172.check
  30. +1 −1 test/files/run/t5256a.check
  31. +1 −1 test/files/run/t5256b.check
  32. +1 −1 test/files/run/t5256d.check
  33. +1 −1 test/files/run/t5256e.check
  34. +2 −2 test/files/run/t5256f.check
  35. +1 −1 test/files/scalap/abstractClass/result.test
  36. +1 −1 test/files/scalap/abstractMethod/result.test
  37. +1 −1 test/files/scalap/cbnParam/result.test
  38. +2 −2 test/files/scalap/classPrivate/result.test
  39. +1 −1 test/files/scalap/classWithExistential/result.test
  40. +1 −1 test/files/scalap/classWithSelfAnnotation/result.test
  41. +1 −1 test/files/scalap/covariantParam/result.test
  42. +2 −2 test/files/scalap/defaultParameter/result.test
  43. +1 −1 test/files/scalap/implicitParam/result.test
  44. +1 −1 test/files/scalap/packageObject/result.test
  45. +1 −1 test/files/scalap/paramClauses/result.test
  46. +1 −1 test/files/scalap/paramNames/result.test
  47. +1 −1 test/files/scalap/sequenceParam/result.test
  48. +1 −1 test/files/scalap/simpleClass/result.test
  49. +2 −2 test/files/scalap/traitObject/result.test
  50. +1 −1 test/files/scalap/typeAnnotations/result.test
  51. +1 −1 test/files/scalap/valAndVar/result.test
  52. +1 −1 test/files/scalap/wildcardType/result.test
@@ -37,8 +37,8 @@ trait CompletionOutput {
val pkg = method.ownerChain find (_.isPackageClass) map (_.fullName) getOrElse ""
def relativize(str: String): String = quietString(str stripPrefix (pkg + "."))
- def relativize(tp: Type): String = relativize(tp.normalize.toString)
- def relativize(sym: Symbol): String = relativize(sym.info)
+ def relativize(tp: Type): String = relativize(tp.dealiasWiden.toString)
+ def relativize(sym: Symbol): String = relativize(sym.info)
def braceList(tparams: List[String]) = if (tparams.isEmpty) "" else (tparams map relativize).mkString("[", ", ", "]")
def parenList(params: List[Any]) = params.mkString("(", ", ", ")")
@@ -56,16 +56,16 @@ trait CompletionOutput {
}
)
- def tupleString(tp: Type) = parenList(tp.normalize.typeArgs map relativize)
- def functionString(tp: Type) = tp.normalize.typeArgs match {
+ def tupleString(tp: Type) = parenList(tp.dealiasWiden.typeArgs map relativize)
+ def functionString(tp: Type) = tp.dealiasWiden.typeArgs match {
case List(t, r) => t + " => " + r
case xs => parenList(xs.init) + " => " + xs.last
}
def tparamsString(tparams: List[Symbol]) = braceList(tparams map (_.defString))
def paramsString(params: List[Symbol]) = {
def paramNameString(sym: Symbol) = if (sym.isSynthetic) "" else sym.nameString + ": "
- def paramString(sym: Symbol) = paramNameString(sym) + typeToString(sym.info.normalize)
+ def paramString(sym: Symbol) = paramNameString(sym) + typeToString(sym.info.dealiasWiden)
val isImplicit = params.nonEmpty && params.head.isImplicit
val strs = (params map paramString) match {
@@ -550,7 +550,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
// normalize non-public types so we don't see protected aliases like Self
def normalizeNonPublic(tp: Type) = tp match {
- case TypeRef(_, sym, _) if sym.isAliasType && !sym.isPublic => tp.normalize
+ case TypeRef(_, sym, _) if sym.isAliasType && !sym.isPublic => tp.dealias
case _ => tp
}
@@ -443,8 +443,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, args) =>
- matchesPtView(tp, args.head, args.tail.head, undet)
+ case TypeRef(_, Function1.Sym, arg1 :: arg2 :: Nil) =>
+ matchesPtView(tp, arg1, arg2, undet)
case _ =>
false
}
@@ -488,7 +488,7 @@ trait Implicits {
loop(restpe, pt)
else pt match {
case tr @ TypeRef(pre, sym, args) =>
- if (sym.isAliasType) loop(tp, pt.normalize)
+ if (sym.isAliasType) loop(tp, pt.dealias)
else if (sym.isAbstractType) loop(tp, pt.bounds.lo)
else {
val len = args.length - 1
@@ -532,18 +532,15 @@ trait Implicits {
* to a final true or false.
*/
private def isPlausiblySubType(tp1: Type, tp2: Type) = !isImpossibleSubType(tp1, tp2)
- private def isImpossibleSubType(tp1: Type, tp2: Type) = tp1.normalize.widen match {
- case tr1 @ TypeRef(_, sym1, _) =>
- // We can only rule out a subtype relationship if the left hand
- // side is a class, else we may not know enough.
- sym1.isClass && (tp2.normalize.widen match {
- case TypeRef(_, sym2, _) =>
- sym2.isClass && !(sym1 isWeakSubClass sym2)
- case RefinedType(parents, decls) =>
- decls.nonEmpty &&
- tr1.member(decls.head.name) == NoSymbol
- case _ => false
- })
+ private def isImpossibleSubType(tp1: Type, tp2: Type) = tp1.dealiasWiden match {
+ // We can only rule out a subtype relationship if the left hand
+ // side is a class, else we may not know enough.
+ case tr1 @ TypeRef(_, sym1, _) if sym1.isClass =>
+ tp2.dealiasWiden match {
+ case TypeRef(_, sym2, _) => sym2.isClass && !(sym1 isWeakSubClass sym2)
+ case RefinedType(parents, decls) => decls.nonEmpty && tr1.member(decls.head.name) == NoSymbol
+ case _ => false
+ }
case _ => false
}
@@ -1018,7 +1015,7 @@ trait Implicits {
args foreach (getParts(_))
}
} else if (sym.isAliasType) {
- getParts(tp.normalize)
+ getParts(tp.dealias)
} else if (sym.isAbstractType) {
getParts(tp.bounds.hi)
}
@@ -1049,88 +1046,6 @@ trait Implicits {
infoMap
}
- /** The parts of a type is the smallest set of types that contains
- * - the type itself
- * - the parts of its immediate components (prefix and argument)
- * - the parts of its base types
- * - for alias types and abstract types, we take instead the parts
- * - of their upper bounds.
- * @return For those parts that refer to classes with companion objects that
- * can be accessed with unambiguous stable prefixes, the implicits infos
- * which are members of these companion objects.
-
- private def companionImplicits(tp: Type): Infoss = {
- val partMap = new LinkedHashMap[Symbol, Type]
- val seen = mutable.HashSet[Type]() // cycle detection
-
- /** Enter all parts of `tp` into `parts` set.
- * This method is performance critical: about 2-4% of all type checking is spent here
- */
- def getParts(tp: Type) {
- if (seen(tp))
- return
- seen += tp
- tp match {
- case TypeRef(pre, sym, args) =>
- if (sym.isClass) {
- if (!((sym.name == tpnme.REFINE_CLASS_NAME) ||
- (sym.name startsWith tpnme.ANON_CLASS_NAME) ||
- (sym.name == tpnme.ROOT)))
- partMap get sym match {
- case Some(pre1) =>
- if (!(pre =:= pre1)) partMap(sym) = NoType // ambiguous prefix - ignore implicit members
- case None =>
- if (pre.isStable) partMap(sym) = pre
- val bts = tp.baseTypeSeq
- var i = 1
- while (i < bts.length) {
- getParts(bts(i))
- i += 1
- }
- getParts(pre)
- args foreach getParts
- }
- } else if (sym.isAliasType) {
- getParts(tp.normalize)
- } else if (sym.isAbstractType) {
- getParts(tp.bounds.hi)
- }
- case ThisType(_) =>
- getParts(tp.widen)
- case _: SingletonType =>
- getParts(tp.widen)
- case RefinedType(ps, _) =>
- for (p <- ps) getParts(p)
- case AnnotatedType(_, t, _) =>
- getParts(t)
- case ExistentialType(_, t) =>
- getParts(t)
- case PolyType(_, t) =>
- getParts(t)
- case _ =>
- }
- }
-
- getParts(tp)
-
- val buf = new ListBuffer[Infos]
- for ((clazz, pre) <- partMap) {
- if (pre != NoType) {
- val companion = clazz.companionModule
- companion.moduleClass match {
- case mc: ModuleClassSymbol =>
- buf += (mc.implicitMembers map (im =>
- new ImplicitInfo(im.name, singleType(pre, companion), im)))
- case _ =>
- }
- }
- }
- //println("companion implicits of "+tp+" = "+buf.toList) // DEBUG
- buf.toList
- }
-
-*/
-
/** The implicits made available by type `pt`.
* These are all implicits found in companion objects of classes C
* such that some part of `tp` has C as one of its superclasses.
@@ -1258,7 +1173,7 @@ trait Implicits {
implicit def wrapResult(tree: Tree): SearchResult =
if (tree == EmptyTree) SearchFailure else new SearchResult(tree, if (from.isEmpty) EmptyTreeTypeSubstituter else new TreeTypeSubstituter(from, to))
- val tp1 = tp0.normalize
+ val tp1 = tp0.dealias
tp1 match {
case ThisType(_) | SingleType(_, _) =>
// can't generate a reference to a value that's abstracted over by an existential
@@ -44,7 +44,7 @@ trait Infer extends Checkable {
case formal => formal
} else formals
if (isVarArgTypes(formals1) && (removeRepeated || formals.length != nargs)) {
- val ft = formals1.last.normalize.typeArgs.head
@adriaanm

adriaanm Feb 26, 2013

Owner

ok since we're considering type of values

+ val ft = formals1.last.dealiasWiden.typeArgs.head
formals1.init ::: (for (i <- List.range(formals1.length - 1, nargs)) yield ft)
} else formals1
}
@@ -1060,15 +1060,17 @@ trait Infer extends Checkable {
*/
def inferExprInstance(tree: Tree, tparams: List[Symbol], pt: Type = WildcardType, treeTp0: Type = null, keepNothings: Boolean = true, useWeaklyCompatible: Boolean = false): List[Symbol] = {
val treeTp = if(treeTp0 eq null) tree.tpe else treeTp0 // can't refer to tree in default for treeTp0
+ val (targs, tvars) = exprTypeArgs(tparams, treeTp, pt, useWeaklyCompatible)
printInference(
ptBlock("inferExprInstance",
"tree" -> tree,
"tree.tpe"-> tree.tpe,
"tparams" -> tparams,
- "pt" -> pt
+ "pt" -> pt,
+ "targs" -> targs,
+ "tvars" -> tvars
)
)
- val (targs, tvars) = exprTypeArgs(tparams, treeTp, pt, useWeaklyCompatible)
if (keepNothings || (targs eq null)) { //@M: adjustTypeArgs fails if targs==null, neg/t0226
substExpr(tree, tparams, targs, pt)
@@ -1422,9 +1424,9 @@ trait Infer extends Checkable {
}
object approximateAbstracts extends TypeMap {
- def apply(tp: Type): Type = tp.normalize match {
+ def apply(tp: Type): Type = tp.dealiasWiden match {
@adriaanm

adriaanm Feb 26, 2013

Owner

not sure about this one: external calls only come in with proper types, but we may encounter type constructors on recursion

@retronym

retronym Feb 28, 2013

Owner

...but, if normalize yielded a PolyType, it would not match the first case, and would be discarded.

So before/after, we get in the same for this example:

scala> trait U[_[_]]; trait M[A] { type O[a] = (a, A); def m: U[O] }
defined trait U
defined trait M

scala> val t = typeOf[M[Nothing]].decl(newTermName("m")).info
t: $r.intp.global.Type = => U[M.this.O]

scala> typer.infer.approximateAbstracts(t.resultType)
res26: $r.intp.global.analyzer.global.Type = U[M.this.O]

So we're compatible with 2.10.0 wrt HK type refs.

Swinging the pendulum back further towards normalize is interesting, though:

scala> object approximateAbstracts1 extends TypeMap {
     |  def apply(tp: Type): Type = tp.normalize match {
     |    case TypeRef(pre, sym, _) if sym.isAbstractType => WildcardType
     |    case tp1                                          => mapOver(tp1)
     |  }
     |}
defined module approximateAbstracts1

scala> approximateAbstracts1(t.resultType)
res27: $r.intp.global.Type = U[[a](?, ?)]

scala> trait U[_[_]]; trait M[A] { type O[a] = (Int, A); def m: U[O] }
defined trait U
defined trait M

scala> val t = typeOf[M[Nothing]].decl(newTermName("m")).info
t: $r.intp.global.Type = => U[M.this.O]

scala> approximateAbstracts1(t.resultType)
res28: $r.intp.global.Type = U[[a](Int, ?)]
@adriaanm

adriaanm Mar 2, 2013

Owner

cool, yeah, that's a better approximation, though we could probably content ourselves with U[?](yay! another kind-polymorphic type)

@paulp

paulp Mar 2, 2013

Contributor

A PolyType as a type arg? It sounds nice, but if that doesn't blow up in twenty different places I'll be surprised.

case TypeRef(pre, sym, _) if sym.isAbstractType => WildcardType
- case _ => mapOver(tp)
+ case _ => mapOver(tp)
}
}
@@ -224,7 +224,7 @@ trait Typers extends Modes with Adaptations with Tags {
case ExistentialType(tparams, tpe) =>
new SubstWildcardMap(tparams).apply(tp)
case TypeRef(_, sym, _) if sym.isAliasType =>
- val tp0 = tp.normalize
+ val tp0 = tp.dealias
val tp1 = dropExistential(tp0)
if (tp1 eq tp0) tp else tp1
@retronym

retronym Feb 26, 2013

Owner

Let's get the ball rolling.

A HK type ref, when normalized, would have yielded a PolyType that would have not progressed further, and hence would have been discarded in favor of the original tp.

So modulo the dodgy T[T] that I've curtailed in the second commit of #2167, dealias looks correct here.

scala> trait M[N[_]]
warning: there were 1 feature warnings; re-run with -feature for details
defined trait M

scala> type T = M[Vector]
defined type alias T

scala> val V = typeOf[T].dealias.typeArguments.head
V: $r.intp.global.Type = Vector

scala> V.normalize
res30: $r.intp.global.Type = [+A]Vector[A]

scala> V.normalize eq typer.dropExistential(V.normalize)
res31: Boolean = true
case _ => tp
@@ -439,7 +439,7 @@ trait Typers extends Modes with Adaptations with Tags {
if (!hiddenSymbols.isEmpty && hiddenSymbols.head == sym &&
sym.isAliasType && sameLength(sym.typeParams, args)) {
hiddenSymbols = hiddenSymbols.tail
- t.normalize
+ t.dealias
@retronym

retronym Feb 26, 2013

Owner

Original call to .normalize added many moons ago in 8414eb#L11R383.

My conclusion here is that sameLength(sym.typeParams, args) excludes HK type refs.

The does mechanism manages to find escaping private types, both before and after this patch.

scala> trait O { private trait T; type M[_]=T}
<console>:7: error: private trait T escapes its defining scope as part of type O.this.T
       trait O { private trait T; type M[_]=T}
                                            ^
} else t
case SingleType(_, sym) =>
checkNoEscape(sym)
@@ -1075,9 +1075,9 @@ trait Typers extends Modes with Adaptations with Tags {
adapt(tree setType restpe, mode, pt, original)
case TypeRef(_, ByNameParamClass, List(arg)) if ((mode & EXPRmode) != 0) => // (2)
adapt(tree setType arg, mode, pt, original)
- case tr @ TypeRef(_, sym, _) if sym.isAliasType && tr.normalize.isInstanceOf[ExistentialType] &&
+ case tr @ TypeRef(_, sym, _) if sym.isAliasType && tr.dealias.isInstanceOf[ExistentialType] &&
((mode & (EXPRmode | LHSmode)) == EXPRmode) =>
- adapt(tree setType tr.normalize.skolemizeExistential(context.owner, tree), mode, pt, original)
+ adapt(tree setType tr.dealias.skolemizeExistential(context.owner, tree), mode, pt, original)
@retronym

retronym Feb 26, 2013

Owner

.normalize on a HK type ref yields a PolyType, not an ExistentialType, so dealias should be sufficient.

case et @ ExistentialType(_, _) if ((mode & (EXPRmode | LHSmode)) == EXPRmode) =>
adapt(tree setType et.skolemizeExistential(context.owner, tree), mode, pt, original)
case PolyType(tparams, restpe) if inNoModes(mode, TAPPmode | PATTERNmode | HKmode) => // (3)
@@ -1147,7 +1147,7 @@ trait Typers extends Modes with Adaptations with Tags {
if (tree1.tpe <:< pt) adapt(tree1, mode, pt, original)
else {
if (inExprModeButNot(mode, FUNmode)) {
- pt.normalize match {
+ pt.dealias match {
@retronym

retronym Feb 26, 2013

Owner

In expression mode here, pt certainly can't be higher kinded, let alone a HK type alias. dealiasWiden wouldn't make sense, as val u = (); 0: u.type is invalid.

👍

case TypeRef(_, sym, _) =>
// note: was if (pt.typeSymbol == UnitClass) but this leads to a potentially
// infinite expansion if pt is constant type ()
@@ -1302,7 +1302,7 @@ trait Typers extends Modes with Adaptations with Tags {
def adaptToMember(qual: Tree, searchTemplate: Type, reportAmbiguous: Boolean = true, saveErrors: Boolean = true): Tree = {
if (isAdaptableWithView(qual)) {
- qual.tpe.widen.normalize match {
+ qual.tpe.dealiasWiden match {
@adriaanm

adriaanm Feb 26, 2013

Owner

proper type, qual is a value

case et: ExistentialType =>
qual setType et.skolemizeExistential(context.owner, qual) // open the existential
case _ =>
@@ -1840,7 +1840,7 @@ trait Typers extends Modes with Adaptations with Tags {
_.typedTemplate(cdef.impl, parentTypes(cdef.impl))
}
val impl2 = finishMethodSynthesis(impl1, clazz, context)
- if (clazz.isTrait && clazz.info.parents.nonEmpty && clazz.info.firstParent.normalize.typeSymbol == AnyClass)
@adriaanm

adriaanm Feb 26, 2013

Owner

can't inherit type constructors

+ if (clazz.isTrait && clazz.info.parents.nonEmpty && clazz.info.firstParent.typeSymbol == AnyClass)
checkEphemeral(clazz, impl2.body)
if ((clazz != ClassfileAnnotationClass) &&
(clazz isNonBottomSubClass ClassfileAnnotationClass))
@@ -3865,7 +3865,7 @@ trait Typers extends Modes with Adaptations with Tags {
val normalizeLocals = new TypeMap {
def apply(tp: Type): Type = tp match {
case TypeRef(pre, sym, args) =>
- if (sym.isAliasType && containsLocal(tp)) apply(tp.normalize)
+ if (sym.isAliasType && containsLocal(tp)) apply(tp.dealias)
@adriaanm

adriaanm Feb 26, 2013

Owner

this could be wrong

else {
if (pre.isVolatile)
InferTypeWithVolatileTypeSelectionError(tree, pre)
@@ -4393,7 +4393,13 @@ trait Typers extends Modes with Adaptations with Tags {
def typedNew(tree: New) = {
val tpt = tree.tpt
val tpt1 = {
- val tpt0 = typedTypeConstructor(tpt)
+ // This way typedNew always returns a dealiased type. This used to happen by accident
+ // for instantiations without type arguments due to ad hoc code in typedTypeConstructor,
+ // and annotations depended on it (to the extent that they worked, which they did
+ // not when given a parameterized type alias which dealiased to an annotation.)
+ // typedTypeConstructor dealiases nothing now, but it makes sense for a "new" to always be
+ // given a dealiased type.
+ val tpt0 = typedTypeConstructor(tpt) modifyType (_.dealias)
@adriaanm

adriaanm Feb 26, 2013

Owner

ok, can't new a type constructor (yes, confusing terminology)

@retronym

retronym Feb 28, 2013

Owner

I've lodged a SI-7194, which I discovered while poking at this. But that bug predates this change:

scala> class C[A]; new ({type T[A] = C[A]})#T[Int]

adapt should have turned dc: TypeTreeWithDeferredRefCheck into tpt: TypeTree, with tpt.original == dc
if (checkStablePrefixClassType(tpt0))
if (tpt0.hasSymbol && !tpt0.symbol.typeParams.isEmpty) {
context.undetparams = cloneSymbols(tpt0.symbol.typeParams)
@@ -5733,29 +5739,18 @@ trait Typers extends Modes with Adaptations with Tags {
def typedTypeConstructor(tree: Tree, mode: Int): Tree = {
val result = typed(tree, forTypeMode(mode) | FUNmode, WildcardType)
- val restpe = result.tpe.normalize // normalize to get rid of type aliases for the following check (#1241)
- if (!phase.erasedTypes && restpe.isInstanceOf[TypeRef] && !restpe.prefix.isStable && !context.unit.isJava) {
- // The isJava exception if OK only because the only type constructors scalac gets
- // to see are those in the signatures. These do not need a unique object as a prefix.
- // The situation is different for new's and super's, but scalac does not look deep
- // enough to see those. See #3938
- ConstructorPrefixError(tree, restpe)
- } else {
- //@M fix for #2208
- // if there are no type arguments, normalization does not bypass any checks, so perform it to get rid of AnyRef
- if (result.tpe.typeArgs.isEmpty) {
- // minimal check: if(result.tpe.typeSymbolDirect eq AnyRefClass) {
- // must expand the fake AnyRef type alias, because bootstrapping (init in Definitions) is not
- // designed to deal with the cycles in the scala package (ScalaObject extends
- // AnyRef, but the AnyRef type alias is entered after the scala package is
- // loaded and completed, so that ScalaObject is unpickled while AnyRef is not
- // yet defined )
- // !!! TODO - revisit now that ScalaObject is gone.
- result setType(restpe)
- } else { // must not normalize: type application must be (bounds-)checked (during RefChecks), see #2208
+ // get rid of type aliases for the following check (#1241)
+ result.tpe.dealias match {
+ case restpe @ TypeRef(pre, _, _) if !phase.erasedTypes && !pre.isStable && !context.unit.isJava =>
+ // The isJava exception if OK only because the only type constructors scalac gets
+ // to see are those in the signatures. These do not need a unique object as a prefix.
+ // The situation is different for new's and super's, but scalac does not look deep
+ // enough to see those. See #3938
+ ConstructorPrefixError(tree, restpe)
+ case _ =>
+ // must not normalize: type application must be (bounds-)checked (during RefChecks), see #2208
// during uncurry (after refchecks), all types are normalized
result
- }
}
}
Oops, something went wrong.

0 comments on commit e5da30b

Please sign in to comment.