diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Typers.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 146 |
1 files changed, 72 insertions, 74 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 9d390476db..386eec207a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -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 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 } 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) 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 { 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 { 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) + if (clazz.isTrait && clazz.info.parents.nonEmpty && clazz.info.firstParent.typeSymbol == AnyClass) checkEphemeral(clazz, impl2.body) if ((clazz != ClassfileAnnotationClass) && (clazz isNonBottomSubClass ClassfileAnnotationClass)) @@ -2070,57 +2070,60 @@ trait Typers extends Modes with Adaptations with Tags { */ def computeParamAliases(clazz: Symbol, vparamss: List[List[ValDef]], rhs: Tree) { debuglog(s"computing param aliases for $clazz:${clazz.primaryConstructor.tpe}:$rhs") + val pending = ListBuffer[AbsTypeError]() + + // !!! This method is redundant with other, less buggy ones. def decompose(call: Tree): (Tree, List[Tree]) = call match { case Apply(fn, args) => - val (superConstr, args1) = decompose(fn) + // an object cannot be allowed to pass a reference to itself to a superconstructor + // because of initialization issues; SI-473, SI-3913, SI-6928. + foreachSubTreeBoundTo(args, clazz) { tree => + if (tree.symbol.isModule) + pending += SuperConstrReferenceError(tree) + tree match { + case This(qual) => + pending += SuperConstrArgsThisReferenceError(tree) + case _ => () + } + } + val (superConstr, preArgs) = decompose(fn) val params = fn.tpe.params - val args2 = if (params.isEmpty || !isRepeatedParamType(params.last.tpe)) args - else args.take(params.length - 1) :+ EmptyTree - assert(sameLength(args2, params) || call.isErrorTyped, "mismatch " + clazz + " " + (params map (_.tpe)) + " " + args2)//debug - (superConstr, args1 ::: args2) - case Block(stats, expr) if !stats.isEmpty => - decompose(stats.last) + // appending a dummy tree to represent Nil for an empty varargs (is this really necessary?) + val applyArgs = if (args.length < params.length) args :+ EmptyTree else args take params.length + + assert(sameLength(applyArgs, params) || call.isErrorTyped, + s"arity mismatch but call is not error typed: $clazz (params=$params, args=$applyArgs)") + + (superConstr, preArgs ::: applyArgs) + case Block(_ :+ superCall, _) => + decompose(superCall) case _ => - (call, List()) + (call, Nil) } val (superConstr, superArgs) = decompose(rhs) assert(superConstr.symbol ne null, superConstr)//debug - - val pending = ListBuffer[AbsTypeError]() - // an object cannot be allowed to pass a reference to itself to a superconstructor - // because of initialization issues; bug #473 - foreachSubTreeBoundTo(superArgs, clazz) { tree => - if (tree.symbol.isModule) - pending += SuperConstrReferenceError(tree) - tree match { - case This(qual) => - pending += SuperConstrArgsThisReferenceError(tree) - case _ => () - } - } - - if (superConstr.symbol.isPrimaryConstructor) { - val superClazz = superConstr.symbol.owner - if (!superClazz.isJavaDefined) { - val superParamAccessors = superClazz.constrParamAccessors - if (sameLength(superParamAccessors, superArgs)) { - for ((superAcc, superArg @ Ident(name)) <- superParamAccessors zip superArgs) { - if (vparamss.exists(_.exists(_.symbol == superArg.symbol))) { - var alias = superAcc.initialize.alias - if (alias == NoSymbol) - alias = superAcc.getter(superAcc.owner) - if (alias != NoSymbol && - superClazz.info.nonPrivateMember(alias.name) != alias) - alias = NoSymbol - if (alias != NoSymbol) { - var ownAcc = clazz.info.decl(name).suchThat(_.isParamAccessor) - if ((ownAcc hasFlag ACCESSOR) && !ownAcc.isDeferred) - ownAcc = ownAcc.accessed - if (!ownAcc.isVariable && !alias.accessed.isVariable) { - debuglog("" + ownAcc + " has alias "+alias.fullLocationString) //debug - ownAcc.asInstanceOf[TermSymbol].setAlias(alias) - } - } + def superClazz = superConstr.symbol.owner + def superParamAccessors = superClazz.constrParamAccessors + + // associate superclass paramaccessors with their aliases + if (superConstr.symbol.isPrimaryConstructor && !superClazz.isJavaDefined && sameLength(superParamAccessors, superArgs)) { + for ((superAcc, superArg @ Ident(name)) <- superParamAccessors zip superArgs) { + if (mexists(vparamss)(_.symbol == superArg.symbol)) { + val alias = ( + superAcc.initialize.alias + orElse (superAcc getter superAcc.owner) + filter (alias => superClazz.info.nonPrivateMember(alias.name) != alias) + ) + if (alias.exists && !alias.accessed.isVariable) { + val ownAcc = clazz.info decl name suchThat (_.isParamAccessor) match { + case acc if !acc.isDeferred && acc.hasAccessorFlag => acc.accessed + case acc => acc + } + ownAcc match { + case acc: TermSymbol if !acc.isVariable => + debuglog(s"$acc has alias ${alias.fullLocationString}") + acc setAlias alias + case _ => } } } @@ -3865,7 +3868,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) else { if (pre.isVolatile) InferTypeWithVolatileTypeSelectionError(tree, pre) @@ -4393,7 +4396,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) if (checkStablePrefixClassType(tpt0)) if (tpt0.hasSymbol && !tpt0.symbol.typeParams.isEmpty) { context.undetparams = cloneSymbols(tpt0.symbol.typeParams) @@ -5733,29 +5742,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 - } } } |