From 1850ddf380789e364813111282af5ff11e65b52c Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 11 May 2013 13:02:53 -0700 Subject: Corralling Modes into a smaller pen. Attempting to reduce the frequency of low-level operations with modes. I mean stuff like this: if ((mode & (EXPRmode | LHSmode)) == EXPRmode) THey don't make those ten line boolean guards any easier to understand. Hopefully this will lead us toward eliminating some of the modes entirely, or at least better isolating their logic rather than having it interspersed at arbitrary points throughout the typer. Modes are in their entirety a leaked implementation detail. Typing a tree requires a tree and optionally an expected type. It shouldn't require a bucket of state bits. In subsequent commits I will start eliminating them. This commit also breaks adapt down into more digestible chunks. --- .../scala/reflect/macros/runtime/Typers.scala | 2 +- .../scala/tools/nsc/javac/JavaParsers.scala | 2 +- .../scala/tools/nsc/typechecker/Duplicators.scala | 2 +- .../tools/nsc/typechecker/TypeDiagnostics.scala | 6 +- .../scala/tools/nsc/typechecker/Typers.scala | 465 +++++++++++---------- 5 files changed, 248 insertions(+), 229 deletions(-) (limited to 'src/compiler/scala') diff --git a/src/compiler/scala/reflect/macros/runtime/Typers.scala b/src/compiler/scala/reflect/macros/runtime/Typers.scala index 398770ab35..0ebcf43de0 100644 --- a/src/compiler/scala/reflect/macros/runtime/Typers.scala +++ b/src/compiler/scala/reflect/macros/runtime/Typers.scala @@ -24,7 +24,7 @@ trait Typers { // typechecking uses silent anyways (e.g. in typedSelect), so you'll only waste your time // I'd advise fixing the root cause: finding why the context is not set to report errors // (also see reflect.runtime.ToolBoxes.typeCheckExpr for a workaround that might work for you) - wrapper(callsiteTyper.silent(_.typed(tree, Mode.EXPRmode, pt)) match { + wrapper(callsiteTyper.silent(_.typed(tree, pt)) match { case universe.analyzer.SilentResultValue(result) => macroLogVerbose(result) result diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 786754ce4c..5efdb036a7 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -494,7 +494,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { atPos(pos) { New(Select(scalaDot(nme.runtime), tpnme.AnnotationDefaultATTR), Nil) } - mods1 = mods1 withAnnotations List(annot) + mods1 = mods1 withAnnotations annot :: Nil skipTo(SEMI) accept(SEMI) blankExpr diff --git a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala index b9e4b4f591..5d627e13a5 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala @@ -331,7 +331,7 @@ abstract class Duplicators extends Analyzer { super.typed(atPos(tree.pos)(tree1)) */ case Match(scrut, cases) => - val scrut1 = typed(scrut, EXPRmode | BYVALmode, WildcardType) + val scrut1 = typedExprByValue(scrut) val scrutTpe = scrut1.tpe.widen val cases1 = { if (scrutTpe.isFinalType) cases filter { diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index 5146cf6fa7..b2a6e7340d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -569,11 +569,7 @@ trait TypeDiagnostics { } // The checkDead call from typedArg is more selective. - def inMode(mode: Mode, tree: Tree): Tree = { - val modeOK = (mode & (EXPRmode | BYVALmode | POLYmode)) == (EXPRmode | BYVALmode) - if (modeOK) apply(tree) - else tree - } + def inMode(mode: Mode, tree: Tree): Tree = if (mode.typingMonoExprByValue) apply(tree) else tree } private def symWasOverloaded(sym: Symbol) = sym.owner.isClass && sym.owner.info.member(sym.name).isOverloaded diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 001808e6bc..6969768ef3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -512,8 +512,6 @@ trait Typers extends Adaptations with Tags { typer1 } else this - final val xtypes = false - /** Is symbol defined and not stale? */ def reallyExists(sym: Symbol) = { @@ -534,13 +532,19 @@ trait Typers extends Adaptations with Tags { /** Does the context of tree `tree` require a stable type? */ - private def isStableContext(tree: Tree, mode: Mode, pt: Type) = - isNarrowable(tree.tpe) && mode.inExprMode && mode.inNone(LHSmode) && - (xtypes || - (pt.isStable || - mode.inAll(QUALmode) && !tree.symbol.isConstant || - pt.typeSymbol.isAbstractType && pt.bounds.lo.isStable && !(tree.tpe <:< pt)) || - pt.typeSymbol.isRefinementClass && !(tree.tpe <:< pt)) + private def isStableContext(tree: Tree, mode: Mode, pt: Type) = { + def ptSym = pt.typeSymbol + def expectsStable = ( + pt.isStable + || mode.inQualMode && !tree.symbol.isConstant + || !(tree.tpe <:< pt) && (ptSym.isAbstractType && pt.bounds.lo.isStable || ptSym.isRefinementClass) + ) + + ( isNarrowable(tree.tpe) + && mode.typingExprNotLhs + && expectsStable + ) + } /** Make symbol accessible. This means: * If symbol refers to package object, insert `.package` as second to last selector. @@ -600,7 +604,7 @@ trait Typers extends Adaptations with Tags { def fail() = NotAValueError(tree, sym) if (tree.isErrorTyped) tree - else if (mode.inPatternNotFunMode && tree.isTerm) { // (1) + else if (mode.typingPatternNotFun && tree.isTerm) { // (1) if (sym.isValue) { val tree1 = checkStable(tree) // A module reference in a pattern has type Foo.type, not "object Foo" @@ -608,7 +612,7 @@ trait Typers extends Adaptations with Tags { else tree1 } else fail() - } else if ((mode & (EXPRmode | QUALmode)) == EXPRmode && !sym.isValue && !phase.erasedTypes) { // (2) + } else if (mode.inExprModeButNot(QUALmode) && !sym.isValue && !phase.erasedTypes) { // (2) fail() } else { if (sym.isStable && pre.isStable && !isByNameParamType(tree.tpe) && @@ -803,9 +807,11 @@ trait Typers extends Adaptations with Tags { * If all this fails, error */ protected def adapt(tree: Tree, mode: Mode, pt: Type, original: Tree = EmptyTree): Tree = { + def hasUndets = context.undetparams.nonEmpty + def hasUndetsInMonoMode = hasUndets && !mode.inPolyMode def adaptToImplicitMethod(mt: MethodType): Tree = { - if (context.undetparams.nonEmpty) { // (9) -- should revisit dropped condition `(mode & POLYmode) == 0` + if (hasUndets) { // (9) -- should revisit dropped condition `hasUndetsInMonoMode` // dropped so that type args of implicit method are inferred even if polymorphic expressions are allowed // needed for implicits in 2.8 collection library -- maybe once #3346 is fixed, we can reinstate the condition? context.undetparams = inferExprInstance(tree, context.extractUndetparams(), pt, @@ -847,27 +853,27 @@ trait Typers extends Adaptations with Tags { case _ => tree.symbol } if (!meth.isConstructor && isFunctionType(pt)) { // (4.2) - debuglog("eta-expanding " + tree + ":" + tree.tpe + " to " + pt) + debuglog(s"eta-expanding $tree: ${tree.tpe} to $pt") checkParamsConvertible(tree, tree.tpe) val tree0 = etaExpand(context.unit, tree, this) - if (context.undetparams.nonEmpty) { - // #2624: need to infer type arguments for eta expansion of a polymorphic method - // context.undetparams contains clones of meth.typeParams (fresh ones were generated in etaExpand) - // need to run typer on tree0, since etaExpansion sets the tpe's of its subtrees to null - // can't type with the expected type, as we can't recreate the setup in (3) without calling typed - // (note that (3) does not call typed to do the polymorphic type instantiation -- - // it is called after the tree has been typed with a polymorphic expected result type) + // #2624: need to infer type arguments for eta expansion of a polymorphic method + // context.undetparams contains clones of meth.typeParams (fresh ones were generated in etaExpand) + // need to run typer on tree0, since etaExpansion sets the tpe's of its subtrees to null + // can't type with the expected type, as we can't recreate the setup in (3) without calling typed + // (note that (3) does not call typed to do the polymorphic type instantiation -- + // it is called after the tree has been typed with a polymorphic expected result type) + if (hasUndets) instantiate(typed(tree0, mode, WildcardType), mode, pt) - } else + else typed(tree0, mode, pt) - } else if (!meth.isConstructor && mt.params.isEmpty) { // (4.3) - adapt(typed(Apply(tree, List()) setPos tree.pos), mode, pt, original) - } else if (context.implicitsEnabled) { + } + else if (!meth.isConstructor && mt.params.isEmpty) // (4.3) + adapt(typed(Apply(tree, Nil) setPos tree.pos), mode, pt, original) + else if (context.implicitsEnabled) MissingArgsForMethodTpeError(tree, meth) - } else { + else setError(tree) - } } def adaptType(): Tree = { @@ -885,7 +891,8 @@ trait Typers extends Adaptations with Tags { // @M TODO: why do kind-* tree's have symbols, while higher-kinded ones don't? MissingTypeParametersError(tree) } else if ( // (7.1) @M: check kind-arity - // @M: removed check for tree.hasSymbolField and replace tree.symbol by tree.tpe.symbol (TypeTree's must also be checked here, and they don't directly have a symbol) + // @M: removed check for tree.hasSymbolField and replace tree.symbol by tree.tpe.symbol + // (TypeTree's must also be checked here, and they don't directly have a symbol) mode.inHKMode && // @M: don't check tree.tpe.symbol.typeParams. check tree.tpe.typeParams!!! // (e.g., m[Int] --> tree.tpe.symbol.typeParams.length == 1, tree.tpe.typeParams.length == 0!) @@ -1024,6 +1031,7 @@ trait Typers extends Adaptations with Tags { assert(!mode.inHKMode, mode) //@M val adapted = adaptToName(tree, nme.apply) def stabilize0(pre: Type): Tree = stabilize(adapted, pre, EXPRmode | QUALmode, WildcardType) + // TODO reconcile the overlap between Typers#stablize and TreeGen.stabilize val qual = adapted match { case This(_) => @@ -1044,30 +1052,200 @@ trait Typers extends Adaptations with Tags { Select(qual setPos tree.pos.makeTransparent, nme.apply) } } + def adaptConstant(value: Constant): Tree = { + val sym = tree.symbol + if (sym != null && sym.isDeprecated) { + val msg = sym.toString + sym.locationString + " is deprecated: " + sym.deprecationMessage.getOrElse("") + unit.deprecationWarning(tree.pos, msg) + } + treeCopy.Literal(tree, value) + } + + // Ignore type errors raised in later phases that are due to mismatching types with existential skolems + // We have lift crashing in 2.9 with an adapt failure in the pattern matcher. + // Here's my hypothsis why this happens. The pattern matcher defines a variable of type + // + // val x: T = expr + // + // where T is the type of expr, but T contains existential skolems ts. + // In that case, this value definition does not typecheck. + // The value definition + // + // val x: T forSome { ts } = expr + // + // would typecheck. Or one can simply leave out the type of the `val`: + // + // val x = expr + // + // SI-6029 shows another case where we also fail (in uncurry), but this time the expected + // type is an existential type. + // + // The reason for both failures have to do with the way we (don't) transform + // skolem types along with the trees that contain them. We'd need a + // radically different approach to do it. But before investing a lot of time to + // to do this (I have already sunk 3 full days with in the end futile attempts + // to consistently transform skolems and fix 6029), I'd like to + // investigate ways to avoid skolems completely. + // + // upd. The same problem happens when we try to typecheck the result of macro expansion against its expected type + // (which is the return type of the macro definition instantiated in the context of expandee): + // + // Test.scala:2: error: type mismatch; + // found : $u.Expr[Class[_ <: Object]] + // required: reflect.runtime.universe.Expr[Class[?0(in value )]] where type ?0(in value ) <: Object + // scala.reflect.runtime.universe.reify(new Object().getClass) + // ^ + // Therefore following Martin's advice I use this logic to recover from skolem errors after macro expansions + // (by adding the ` || tree.attachments.get[MacroExpansionAttachment].isDefined` clause to the conditional above). + // + def adaptMismatchedSkolems() = { + def canIgnoreMismatch = ( + !context.reportErrors && isPastTyper + || tree.attachments.get[MacroExpansionAttachment].isDefined + ) + def bound = pt match { + case ExistentialType(qs, _) => qs + case _ => Nil + } + def msg = sm""" + |Recovering from existential or skolem type error in + | $tree + |with type: ${tree.tpe} + | pt: $pt + | context: ${context.tree} + | adapted + """.trim + + val boundOrSkolems = if (canIgnoreMismatch) bound ++ pt.skolemsExceptMethodTypeParams else Nil + boundOrSkolems match { + case Nil => AdaptTypeError(tree, tree.tpe, pt) ; setError(tree) + case _ => logResult(msg)(adapt(tree, mode, deriveTypeWithWildcards(boundOrSkolems)(pt))) + } + } + + def fallbackAfterVanillaAdapt(): Tree = { + def isPopulatedPattern = { + if ((tree.symbol ne null) && tree.symbol.isModule) + inferModulePattern(tree, pt) + + isPopulated(tree.tpe, approximateAbstracts(pt)) + } + if (mode.inPatternMode && isPopulatedPattern) + return tree + + val tree1 = constfold(tree, pt) // (10) (11) + if (tree1.tpe <:< pt) + return adapt(tree1, mode, pt, original) + + if (mode.typingExprNotFun) { + // The <: Any requirement inhibits attempts to adapt continuation types + // to non-continuation types. + if (tree.tpe <:< AnyClass.tpe) pt.dealias match { + case TypeRef(_, UnitClass, _) => // (12) + if (settings.warnValueDiscard) + context.unit.warning(tree.pos, "discarded non-Unit value") + return typedPos(tree.pos, mode, pt)(Block(List(tree), Literal(Constant(())))) + case TypeRef(_, sym, _) if isNumericValueClass(sym) && isNumericSubType(tree.tpe, pt) => + if (settings.warnNumericWiden) + context.unit.warning(tree.pos, "implicit numeric widening") + return typedPos(tree.pos, mode, pt)(Select(tree, "to" + sym.name)) + case _ => + } + if (pt.dealias.annotations.nonEmpty && canAdaptAnnotations(tree, this, mode, pt)) // (13) + return typed(adaptAnnotations(tree, this, mode, pt), mode, pt) + + if (hasUndets) + return instantiate(tree, mode, pt) + + if (context.implicitsEnabled && !pt.isError && !tree.isErrorTyped) { + // (14); the condition prevents chains of views + debuglog("inferring view from " + tree.tpe + " to " + pt) + inferView(tree, tree.tpe, pt, reportAmbiguous = true) match { + case EmptyTree => + case coercion => + def msg = "inferred view from " + tree.tpe + " to " + pt + " = " + coercion + ":" + coercion.tpe + if (settings.logImplicitConv) + unit.echo(tree.pos, msg) + + debuglog(msg) + val silentContext = context.makeImplicit(context.ambiguousErrors) + val res = newTyper(silentContext).typed( + new ApplyImplicitView(coercion, List(tree)) setPos tree.pos, mode, pt) + silentContext.firstError match { + case Some(err) => context.issue(err) + case None => return res + } + } + } + } + + debuglog("error tree = " + tree) + if (settings.debug && settings.explaintypes) + explainTypes(tree.tpe, pt) + + if (tree.tpe.isErroneous || pt.isErroneous) + setError(tree) + else + adaptMismatchedSkolems() + } + + def vanillaAdapt(tree: Tree) = { + def applyPossible = { + def applyMeth = member(adaptToName(tree, nme.apply), nme.apply) + dyna.acceptsApplyDynamic(tree.tpe) || ( + if (mode.inTappMode) + tree.tpe.typeParams.isEmpty && applyMeth.filter(!_.tpe.typeParams.isEmpty) != NoSymbol + else + applyMeth.filter(_.tpe.paramSectionCount > 0) != NoSymbol + ) + } + def shouldInsertApply(tree: Tree) = mode.typingExprFun && { + tree.tpe match { + case _: MethodType | _: OverloadedType | _: PolyType => false + case _ => applyPossible + } + } + if (tree.isType) + adaptType() + else if (mode.typingPatternFun) + adaptConstrPattern() + else if (shouldInsertApply(tree)) + insertApply() + else if (hasUndetsInMonoMode) { // (9) + assert(!mode.inHKMode, mode) //@M + if (mode.typingExprNotFun && pt.typeSymbol == UnitClass) + instantiateExpectingUnit(tree, mode) + else + instantiate(tree, mode, pt) + } + else if (tree.tpe <:< pt) + tree + else + fallbackAfterVanillaAdapt() + } + def expandMacroAndVanillaAdapt(): Tree = { + if (mode.typingExprNotFun && treeInfo.isMacroApplication(tree)) { + val tree1 = macroExpandApply(this, tree, mode, pt) + if (tree == tree1) vanillaAdapt(tree) else tree1 + } + else vanillaAdapt(tree) + } // begin adapt tree.tpe match { case atp @ AnnotatedType(_, _, _) if canAdaptAnnotations(tree, this, mode, pt) => // (-1) adaptAnnotations(tree, this, mode, pt) case ct @ ConstantType(value) if mode.inNone(TYPEmode | FUNmode) && (ct <:< pt) && canAdaptConstantTypeToLiteral => // (0) - val sym = tree.symbol - if (sym != null && sym.isDeprecated) { - val msg = sym.toString + sym.locationString + " is deprecated: " + sym.deprecationMessage.getOrElse("") - unit.deprecationWarning(tree.pos, msg) - } - treeCopy.Literal(tree, value) + adaptConstant(value) case OverloadedType(pre, alts) if !mode.inFunMode => // (1) inferExprAlternative(tree, pt) adapt(tree, mode, pt, original) case NullaryMethodType(restpe) => // (2) adapt(tree setType restpe, mode, pt, original) - case TypeRef(_, ByNameParamClass, List(arg)) if mode.inExprMode => // (2) + case TypeRef(_, ByNameParamClass, arg :: Nil) if mode.inExprMode => // (2) adapt(tree setType arg, mode, pt, original) - case tr @ TypeRef(_, sym, _) if sym.isAliasType && tr.dealias.isInstanceOf[ExistentialType] && - ((mode & (EXPRmode | LHSmode)) == EXPRmode) => - 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 tp if mode.typingExprNotLhs && isExistentialType(tp) => + adapt(tree setType tp.dealias.skolemizeExistential(context.owner, tree), mode, pt, original) case PolyType(tparams, restpe) if mode.inNone(TAPPmode | PATTERNmode | HKmode) => // (3) // assert((mode & HKmode) == 0) //@M a PolyType in HKmode represents an anonymous type function, // we're in HKmode since a higher-kinded type is expected --> hence, don't implicitly apply it to type params! @@ -1077,174 +1255,21 @@ trait Typers extends Adaptations with Tags { // -- are we sure we want to expand aliases this early? // -- what caused this change in behaviour?? val tparams1 = cloneSymbols(tparams) - val tree1 = if (tree.isType) tree - else TypeApply(tree, tparams1 map (tparam => - TypeTree(tparam.tpeHK) setPos tree.pos.focus)) setPos tree.pos + val tree1 = ( + if (tree.isType) tree + else TypeApply(tree, tparams1 map (tparam => TypeTree(tparam.tpeHK) setPos tree.pos.focus)) setPos tree.pos + ) context.undetparams ++= tparams1 notifyUndetparamsAdded(tparams1) adapt(tree1 setType restpe.substSym(tparams, tparams1), mode, pt, original) - case mt: MethodType if mt.isImplicit && ((mode & (EXPRmode | FUNmode | LHSmode)) == EXPRmode) => // (4.1) - adaptToImplicitMethod(mt) - case mt: MethodType if (((mode & (EXPRmode | FUNmode | LHSmode)) == EXPRmode) && - (context.undetparams.isEmpty || mode.inPolyMode)) && !treeInfo.isMacroApplicationOrBlock(tree) => + case mt: MethodType if mode.typingExprNotFunNotLhs && mt.isImplicit => // (4.1) + adaptToImplicitMethod(mt) + case mt: MethodType if mode.typingExprNotFunNotLhs && !hasUndetsInMonoMode && !treeInfo.isMacroApplicationOrBlock(tree) => instantiateToMethodType(mt) - case _ => - def vanillaAdapt(tree: Tree) = { - def shouldInsertApply(tree: Tree) = mode.inAll(EXPRmode | FUNmode) && (tree.tpe match { - case _: MethodType | _: OverloadedType | _: PolyType => false - case _ => applyPossible - }) - def applyPossible = { - def applyMeth = member(adaptToName(tree, nme.apply), nme.apply) - dyna.acceptsApplyDynamic(tree.tpe) || ( - if (mode.inAll(TAPPmode)) - tree.tpe.typeParams.isEmpty && applyMeth.filter(!_.tpe.typeParams.isEmpty) != NoSymbol - else - applyMeth.filter(_.tpe.paramSectionCount > 0) != NoSymbol - ) - } - if (tree.isType) - adaptType() - else if (mode.inAll(PATTERNmode | FUNmode)) - adaptConstrPattern() - else if (shouldInsertApply(tree)) - insertApply() - else if (!context.undetparams.isEmpty && !mode.inPolyMode) { // (9) - assert(!mode.inHKMode, mode) //@M - if (mode.inExprModeButNot(FUNmode) && pt.typeSymbol == UnitClass) - instantiateExpectingUnit(tree, mode) - else - instantiate(tree, mode, pt) - } else if (tree.tpe <:< pt) { - tree - } else { - def fallBack: Tree = { - if (mode.inPatternMode) { - if ((tree.symbol ne null) && tree.symbol.isModule) - inferModulePattern(tree, pt) - if (isPopulated(tree.tpe, approximateAbstracts(pt))) - return tree - } - val tree1 = constfold(tree, pt) // (10) (11) - if (tree1.tpe <:< pt) adapt(tree1, mode, pt, original) - else { - if (mode.inExprModeButNot(FUNmode)) { - pt.dealias match { - // The <: Any requirement inhibits attempts to adapt continuation types - // to non-continuation types. - case TypeRef(_, sym, _) if tree.tpe <:< AnyClass.tpe => - // note: was if (pt.typeSymbol == UnitClass) but this leads to a potentially - // infinite expansion if pt is constant type () - if (sym == UnitClass) { // (12) - if (settings.warnValueDiscard) - context.unit.warning(tree.pos, "discarded non-Unit value") - return typedPos(tree.pos, mode, pt) { - Block(List(tree), Literal(Constant(()))) - } - } - else if (isNumericValueClass(sym) && isNumericSubType(tree.tpe, pt)) { - if (settings.warnNumericWiden) - context.unit.warning(tree.pos, "implicit numeric widening") - return typedPos(tree.pos, mode, pt) { - Select(tree, "to" + sym.name) - } - } - case AnnotatedType(_, _, _) if canAdaptAnnotations(tree, this, mode, pt) => // (13) - return typed(adaptAnnotations(tree, this, mode, pt), mode, pt) - case _ => - } - if (!context.undetparams.isEmpty) { - return instantiate(tree, mode, pt) - } - if (context.implicitsEnabled && !pt.isError && !tree.isErrorTyped) { - // (14); the condition prevents chains of views - debuglog("inferring view from " + tree.tpe + " to " + pt) - val coercion = inferView(tree, tree.tpe, pt, reportAmbiguous = true) - if (coercion != EmptyTree) { - def msg = "inferred view from " + tree.tpe + " to " + pt + " = " + coercion + ":" + coercion.tpe - if (settings.logImplicitConv) - unit.echo(tree.pos, msg) - - debuglog(msg) - val silentContext = context.makeImplicit(context.ambiguousErrors) - val res = newTyper(silentContext).typed( - new ApplyImplicitView(coercion, List(tree)) setPos tree.pos, mode, pt) - silentContext.firstError match { - case Some(err) => context.issue(err) - case None => return res - } - } - } - } - if (settings.debug) { - log("error tree = " + tree) - if (settings.explaintypes) explainTypes(tree.tpe, pt) - } - - val found = tree.tpe - if (!found.isErroneous && !pt.isErroneous) { - if ((!context.reportErrors && isPastTyper) || tree.attachments.get[MacroExpansionAttachment].isDefined) { - val bound = pt match { - case ExistentialType(qs, _) => qs - case _ => Nil - } - val boundOrSkolems = bound ++ pt.skolemsExceptMethodTypeParams - if (boundOrSkolems.nonEmpty) { - // Ignore type errors raised in later phases that are due to mismatching types with existential skolems - // We have lift crashing in 2.9 with an adapt failure in the pattern matcher. - // Here's my hypothsis why this happens. The pattern matcher defines a variable of type - // - // val x: T = expr - // - // where T is the type of expr, but T contains existential skolems ts. - // In that case, this value definition does not typecheck. - // The value definition - // - // val x: T forSome { ts } = expr - // - // would typecheck. Or one can simply leave out the type of the `val`: - // - // val x = expr - // - // SI-6029 shows another case where we also fail (in uncurry), but this time the expected - // type is an existential type. - // - // The reason for both failures have to do with the way we (don't) transform - // skolem types along with the trees that contain them. We'd need a - // radically different approach to do it. But before investing a lot of time to - // to do this (I have already sunk 3 full days with in the end futile attempts - // to consistently transform skolems and fix 6029), I'd like to - // investigate ways to avoid skolems completely. - // - // upd. The same problem happens when we try to typecheck the result of macro expansion against its expected type - // (which is the return type of the macro definition instantiated in the context of expandee): - // - // Test.scala:2: error: type mismatch; - // found : $u.Expr[Class[_ <: Object]] - // required: reflect.runtime.universe.Expr[Class[?0(in value )]] where type ?0(in value ) <: Object - // scala.reflect.runtime.universe.reify(new Object().getClass) - // ^ - // Therefore following Martin's advice I use this logic to recover from skolem errors after macro expansions - // (by adding the ` || tree.attachments.get[MacroExpansionAttachment].isDefined` clause to the conditional above). - // - log("recovering from existential or skolem type error in tree \n" + tree + "\nwith type " + tree.tpe + "\n expected type = " + pt + "\n context = " + context.tree) - return adapt(tree, mode, deriveTypeWithWildcards(boundOrSkolems)(pt)) - } - } - // create an actual error - AdaptTypeError(tree, found, pt) - } - setError(tree) - } - } - fallBack - } + expandMacroAndVanillaAdapt() } - val tree1 = if (mode.inExprModeButNot(FUNmode) && treeInfo.isMacroApplication(tree)) macroExpandApply(this, tree, mode, pt) else tree - if (tree == tree1) vanillaAdapt(tree1) else tree1 - } } def instantiate(tree: Tree, mode: Mode, pt: Type): Tree = { @@ -2494,7 +2519,7 @@ trait Typers extends Adaptations with Tags { // takes untyped sub-trees of a match and type checks them def typedMatch(selector: Tree, cases: List[CaseDef], mode: Mode, pt: Type, tree: Tree = EmptyTree): Match = { - val selector1 = checkDead(typed(selector, EXPRmode | BYVALmode, WildcardType)) + val selector1 = checkDead(typedExprByValue(selector)) val selectorTp = packCaptured(selector1.tpe.widen).skolemizeExistential(context.owner, selector) val casesTyped = typedCases(cases, selectorTp, pt) @@ -2518,7 +2543,7 @@ trait Typers extends Adaptations with Tags { // TODO: add fallback __match sentinel to predef val matchStrategy: Tree = if (!(newPatternMatching && settings.Xexperimental && context.isNameInScope(vpmName._match))) null // fast path, avoiding the next line if there's no __match to be seen - else newTyper(context.makeImplicit(reportAmbiguousErrors = false)).silent(_.typed(Ident(vpmName._match), EXPRmode, WildcardType), reportAmbiguousErrors = false) orElse (_ => null) + else newTyper(context.makeImplicit(reportAmbiguousErrors = false)).silent(_.typed(Ident(vpmName._match)), reportAmbiguousErrors = false) orElse (_ => null) if (matchStrategy ne null) // virtualize typed((new PureMatchTranslator(this.asInstanceOf[patmat.global.analyzer.Typer] /*TODO*/, matchStrategy)).translateMatch(match_), mode, pt) @@ -2875,7 +2900,7 @@ trait Typers extends Adaptations with Tags { } else newTyper(context.make(stat, exprOwner)) // XXX this creates a spurious dead code warning if an exception is thrown // in a constructor, even if it is the only thing in the constructor. - val result = checkDead(localTyper.typed(stat, EXPRmode | BYVALmode, WildcardType)) + val result = checkDead(localTyper.typedExprByValue(stat)) if (treeInfo.isSelfOrSuperConstrCall(result)) { context.inConstructorSuffix = true @@ -2989,7 +3014,7 @@ trait Typers extends Adaptations with Tags { def typedArg(arg: Tree, mode: Mode, newmode: Mode, pt: Type): Tree = { val typedMode = mode.onlySticky | newmode - val t = withCondConstrTyper((mode & SCCmode) != NOmode)(_.typed(arg, typedMode, pt)) + val t = withCondConstrTyper(mode.inSccMode)(_.typed(arg, typedMode, pt)) checkDead.inMode(typedMode, t) } @@ -3162,7 +3187,7 @@ trait Typers extends Adaptations with Tags { // Depending on user options, may warn or error here if // a Unit or tuple was inserted. Some(t) filter (tupledTree => - !mode.inExprModeButNot(FUNmode) + !mode.typingExprNotFun || tupledTree.symbol == null || checkValidAdaptation(tupledTree, args) ) @@ -4004,13 +4029,9 @@ trait Typers extends Adaptations with Tags { } def typed1(tree: Tree, mode: Mode, pt: Type): Tree = { - def isPatternMode = mode.inPatternMode - def inPatternConstructor = mode.inAll(PATTERNmode | FUNmode) - def isQualifierMode = mode.inAll(QUALmode) - // Lookup in the given class using the root mirror. def lookupInOwner(owner: Symbol, name: Name): Symbol = - if (isQualifierMode) rootMirror.missingHook(owner, name) else NoSymbol + if (mode.inQualMode) rootMirror.missingHook(owner, name) else NoSymbol // Lookup in the given qualifier. Used in last-ditch efforts by typedIdent and typedSelect. def lookupInRoot(name: Name): Symbol = lookupInOwner(rootMirror.RootClass, name) @@ -4127,7 +4148,7 @@ trait Typers extends Adaptations with Tags { else context.owner.newValue(name, tree.pos) if (name != nme.WILDCARD) { - if (mode.inAll(ALTmode)) VariableInPatternAlternativeError(tree) + if (mode.inAltMode) VariableInPatternAlternativeError(tree) namer.enterInScope(sym) } @@ -4185,11 +4206,11 @@ trait Typers extends Adaptations with Tags { // // setter-rewrite has been done above, so rule out methods here, but, wait a minute, why are we assigning to non-variables after erasure?! // (phase.erasedTypes && varsym.isValue && !varsym.isMethod)) { if (varsym.isVariable || varsym.isValue && phase.erasedTypes) { - val rhs1 = typed(rhs, EXPRmode | BYVALmode, lhs1.tpe) + val rhs1 = typedExprByValue(rhs, lhs1.tpe) treeCopy.Assign(tree, lhs1, checkDead(rhs1)) setType UnitClass.tpe } else if(dyna.isDynamicallyUpdatable(lhs1)) { - val rhs1 = typed(rhs, EXPRmode | BYVALmode, WildcardType) + val rhs1 = typedExprByValue(rhs) val t = Apply(lhs1, List(rhs1)) dyna.wrapErrors(t, _.typed1(t, mode, pt)) } @@ -4197,7 +4218,7 @@ trait Typers extends Adaptations with Tags { } def typedIf(tree: If): If = { - val cond1 = checkDead(typed(tree.cond, EXPRmode | BYVALmode, BooleanClass.tpe)) + val cond1 = checkDead(typedExprByValue(tree.cond, BooleanClass.tpe)) // One-legged ifs don't need a lot of analysis if (tree.elsep.isEmpty) return treeCopy.If(tree, cond1, typed(tree.thenp, UnitClass.tpe), tree.elsep) setType UnitClass.tpe @@ -4441,14 +4462,14 @@ trait Typers extends Adaptations with Tags { def normalTypedApply(tree: Tree, fun: Tree, args: List[Tree]) = { val stableApplication = (fun.symbol ne null) && fun.symbol.isMethod && fun.symbol.isStable - val funpt = if (isPatternMode) pt else WildcardType + val funpt = if (mode.inPatternMode) pt else WildcardType val appStart = if (Statistics.canEnable) Statistics.startTimer(failedApplyNanos) else null val opeqStart = if (Statistics.canEnable) Statistics.startTimer(failedOpEqNanos) else null def onError(reportError: => Tree): Tree = { fun match { case Select(qual, name) - if !isPatternMode && nme.isOpAssignmentName(newTermName(name.decode)) => + if !mode.inPatternMode && nme.isOpAssignmentName(newTermName(name.decode)) => val qual1 = typedQualifier(qual) if (treeInfo.isVariableOrGetter(qual1)) { if (Statistics.canEnable) Statistics.stopTimer(failedOpEqNanos, opeqStart) @@ -4780,7 +4801,7 @@ trait Typers extends Adaptations with Tags { def qualifies(sym: Symbol) = ( sym.hasRawInfo && reallyExists(sym) - && !(inPatternConstructor && sym.isMethod && !sym.isStable) + && !(mode.typingPatternFun && sym.isMethod && !sym.isStable) ) /* Attribute an identifier consisting of a simple name or an outer reference. @@ -4839,8 +4860,8 @@ trait Typers extends Adaptations with Tags { def typedIdentOrWildcard(tree: Ident) = { val name = tree.name if (Statistics.canEnable) Statistics.incCounter(typedIdentCount) - if ((name == nme.WILDCARD && mode.inPatternNotFunMode) || - (name == tpnme.WILDCARD && mode.inAll(TYPEmode))) + if ((name == nme.WILDCARD && mode.typingPatternNotFun) || + (name == tpnme.WILDCARD && mode.inTypeMode)) tree setType makeFullyDefined(pt) else typedIdent(tree, name) @@ -5004,7 +5025,7 @@ trait Typers extends Adaptations with Tags { } def typedThrow(tree: Throw) = { - val expr1 = typed(tree.expr, EXPRmode | BYVALmode, ThrowableClass.tpe) + val expr1 = typedExprByValue(tree.expr, ThrowableClass.tpe) treeCopy.Throw(tree, expr1) setType NothingClass.tpe } @@ -5051,7 +5072,7 @@ trait Typers extends Adaptations with Tags { val exprTyped = typed(expr, mode.onlySticky, tptTyped.tpe.deconst) val treeTyped = treeCopy.Typed(tree, exprTyped, tptTyped) - if (isPatternMode) { + if (mode.inPatternMode) { val uncheckedTypeExtractor = extractorForUncheckedType(tpt.pos, tptTyped.tpe) // make fully defined to avoid bounded wildcard types that may be in pt from calling dropExistential (SI-2038) val ptDefined = ensureFullyDefined(pt) @@ -5348,6 +5369,8 @@ trait Typers extends Adaptations with Tags { ret } + def typedExprByValue(tree: Tree, pt: Type = WildcardType): Tree = typed(tree, EXPRmode | BYVALmode, pt) + def typedPos(pos: Position, mode: Mode, pt: Type)(tree: Tree) = typed(atPos(pos)(tree), mode, pt) def typedPos(pos: Position)(tree: Tree) = typed(atPos(pos)(tree)) // TODO: see if this formulation would impose any penalty, since -- cgit v1.2.3 From 751daa9b3825543bd04eaa4eab6438f8410f6040 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 11 May 2013 13:02:53 -0700 Subject: Started eliminating modes. Consolidating the scattered typer state in Context, where it's relatively easy to keep an eye on, rather than threaded throughout the typer in sneaky/sticky bitmasks. The general pattern will be what was once an explicitly passed around bit in Mode becomes an implicitly propagated-as-appropriate bit in Context. In this commit: ALTmode becomes context mode "PatternAlternative" STARmode becomes context mode "StarPatterns" SUPERCONSTRmode becomes context mode "SuperInit" --- src/compiler/scala/tools/nsc/package.scala | 4 - .../scala/tools/nsc/typechecker/Contexts.scala | 37 +++++-- .../scala/tools/nsc/typechecker/Typers.scala | 117 +++++++++++---------- .../scala/tools/reflect/ToolBoxFactory.scala | 3 +- src/reflect/scala/reflect/internal/Mode.scala | 68 +++++------- 5 files changed, 118 insertions(+), 111 deletions(-) (limited to 'src/compiler/scala') diff --git a/src/compiler/scala/tools/nsc/package.scala b/src/compiler/scala/tools/nsc/package.scala index ee1668a38a..761fd79358 100644 --- a/src/compiler/scala/tools/nsc/package.scala +++ b/src/compiler/scala/tools/nsc/package.scala @@ -10,10 +10,6 @@ package object nsc { val Mode = scala.reflect.internal.Mode def EXPRmode = Mode.EXPRmode - def BYVALmode = Mode.BYVALmode - def POLYmode = Mode.POLYmode - def TAPPmode = Mode.TAPPmode - def FUNmode = Mode.FUNmode type Phase = scala.reflect.internal.Phase val NoPhase = scala.reflect.internal.NoPhase diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index e3bb595bd7..0633c1485f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -219,8 +219,14 @@ trait Contexts { self: Analyzer => var namedApplyBlockInfo: Option[(Tree, NamedApplyInfo)] = None var prefix: Type = NoPrefix + def inSuperInit_=(value: Boolean) = this(SuperInit) = value + def inSuperInit = this(SuperInit) def inConstructorSuffix_=(value: Boolean) = this(ConstructorSuffix) = value def inConstructorSuffix = this(ConstructorSuffix) + def inPatAlternative_=(value: Boolean) = this(PatternAlternative) = value + def inPatAlternative = this(PatternAlternative) + def starPatterns_=(value: Boolean) = this(StarPatterns) = value + def starPatterns = this(StarPatterns) def returnsSeen_=(value: Boolean) = this(ReturnsSeen) = value def returnsSeen = this(ReturnsSeen) def inSelfSuperCall_=(value: Boolean) = this(SelfSuperCall) = value @@ -349,6 +355,8 @@ trait Contexts { self: Analyzer => def withImplicitsDisabledAllowEnrichment[T](op: => T): T = withMode(enabled = EnrichmentEnabled, disabled = ImplicitsEnabled)(op) def withMacrosEnabled[T](op: => T): T = withMode(enabled = MacrosEnabled)(op) def withMacrosDisabled[T](op: => T): T = withMode(disabled = MacrosEnabled)(op) + def withStarPatterns[T](op: => T): T = withMode(enabled = StarPatterns)(op) + def withSuperInit[T](op: => T): T = withMode(enabled = SuperInit)(op) /** @return true if the `expr` evaluates to true within a silent Context that incurs no errors */ @inline final def inSilentMode(expr: => Boolean): Boolean = { @@ -1329,18 +1337,29 @@ object ContextMode { // TODO This seems to directly overlap with Mode.SNDTRYmode final val ReTyping: ContextMode = 1 << 10 + /** Are we typechecking pattern alternatives. Formerly ALTmode. */ + final val PatternAlternative: ContextMode = 1 << 11 + + /** Are star patterns allowed. Formerly STARmode. */ + final val StarPatterns: ContextMode = 1 << 12 + + /** Are we typing the "super" in a superclass constructor call super.. Formerly SUPERCONSTRmode. */ + final val SuperInit: ContextMode = 1 << 13 + final val DefaultMode: ContextMode = MacrosEnabled private val contextModeNameMap = Map( - ReportErrors -> "ReportErrors", - BufferErrors -> "BufferErrors", - AmbiguousErrors -> "AmbiguousErrors", - ConstructorSuffix -> "ConstructorSuffix", - SelfSuperCall -> "SelfSuperCall", - ImplicitsEnabled -> "ImplicitsEnabled", - MacrosEnabled -> "MacrosEnabled", - Checking -> "Checking", - ReTyping -> "ReTyping" + ReportErrors -> "ReportErrors", + BufferErrors -> "BufferErrors", + AmbiguousErrors -> "AmbiguousErrors", + ConstructorSuffix -> "ConstructorSuffix", + SelfSuperCall -> "SelfSuperCall", + ImplicitsEnabled -> "ImplicitsEnabled", + MacrosEnabled -> "MacrosEnabled", + Checking -> "Checking", + ReTyping -> "ReTyping", + PatternAlternative -> "PatternAlternative", + StarPatterns -> "StarPatterns" ) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 6969768ef3..f80fede3f9 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -612,7 +612,7 @@ trait Typers extends Adaptations with Tags { else tree1 } else fail() - } else if (mode.inExprModeButNot(QUALmode) && !sym.isValue && !phase.erasedTypes) { // (2) + } else if (mode.in(all = EXPRmode, none = QUALmode) && !sym.isValue && !phase.erasedTypes) { // (2) fail() } else { if (sym.isStable && pre.isStable && !isByNameParamType(tree.tpe) && @@ -3036,13 +3036,13 @@ trait Typers extends Adaptations with Tags { else { // No formals left or * indicates varargs. val isVarArgs = formals.isEmpty || formals.tail.isEmpty && isRepeatedParamType(formals.head) - val typedMode = sticky | ( - if (isVarArgs) STARmode | BYVALmode - else if (isByNameParamType(formals.head)) NOmode - else BYVALmode - ) + val isByName = formals.nonEmpty && isByNameParamType(formals.head) + def typedMode = if (isByName) sticky else sticky | BYVALmode + def body = typedArg(args.head, mode, typedMode, adapted.head) + def arg1 = if (isVarArgs) context.withStarPatterns(body) else body + // formals may be empty, so don't call tail - typedArg(args.head, mode, typedMode, adapted.head) :: loop(args.tail, formals drop 1, adapted.tail) + arg1 :: loop(args.tail, formals drop 1, adapted.tail) } } loop(args0, formals0, adapted0) @@ -3531,7 +3531,7 @@ trait Typers extends Adaptations with Tags { def tryConst(tr: Tree, pt: Type): Option[LiteralAnnotArg] = { // The typed tree may be relevantly different than the tree `tr`, // e.g. it may have encountered an implicit conversion. - val ttree = typed(constfold(tr), EXPRmode, pt) + val ttree = typed(constfold(tr), pt) val const: Constant = ttree match { case l @ Literal(c) if !l.isErroneous => c case tree => tree.tpe match { @@ -3570,7 +3570,7 @@ trait Typers extends Adaptations with Tags { // use of Array.apply[T: ClassTag](xs: T*): Array[T] // and Array.apply(x: Int, xs: Int*): Array[Int] (and similar) case Apply(fun, args) => - val typedFun = typed(fun, mode.forFunMode, WildcardType) + val typedFun = typed(fun, mode.forFunMode) if (typedFun.symbol.owner == ArrayModule.moduleClass && typedFun.symbol.name == nme.apply) pt match { case TypeRef(_, ArrayClass, targ :: _) => @@ -3601,7 +3601,7 @@ trait Typers extends Adaptations with Tags { val treeInfo.Applied(fun0, targs, argss) = ann if (fun0.isErroneous) return finish(ErroneousAnnotation) - val typedFun0 = typed(fun0, mode.forFunMode, WildcardType) + val typedFun0 = typed(fun0, mode.forFunMode) val typedFunPart = ( // If there are dummy type arguments in typeFun part, it suggests we // must type the actual constructor call, not only the select. The value @@ -4148,7 +4148,9 @@ trait Typers extends Adaptations with Tags { else context.owner.newValue(name, tree.pos) if (name != nme.WILDCARD) { - if (mode.inAltMode) VariableInPatternAlternativeError(tree) + if (context.inPatAlternative) + VariableInPatternAlternativeError(tree) + namer.enterInScope(sym) } @@ -4181,7 +4183,7 @@ trait Typers extends Adaptations with Tags { } def typedAssign(lhs: Tree, rhs: Tree): Tree = { - val lhs1 = typed(lhs, EXPRmode | LHSmode, WildcardType) + val lhs1 = typed(lhs, EXPRmode | LHSmode) val varsym = lhs1.symbol // see #2494 for double error message example @@ -4499,7 +4501,7 @@ trait Typers extends Adaptations with Tags { ) val isFirstTry = !noSecondTry && ( fun2 match { - case Select(_, _) => mode inExprModeButNot SNDTRYmode + case Select(_, _) => mode.in(all = EXPRmode, none = SNDTRYmode) case _ => false } ) @@ -4620,7 +4622,7 @@ trait Typers extends Adaptations with Tags { val owntype = ( if (!mix.isEmpty) findMixinSuper(clazz.tpe) - else if (mode.inAll(SUPERCONSTRmode)) clazz.info.firstParent + else if (context.inSuperInit) clazz.info.firstParent else intersectionType(clazz.info.parents) ) treeCopy.Super(tree, qual1, mix) setType SuperType(clazz.thisType, owntype) @@ -4664,7 +4666,7 @@ trait Typers extends Adaptations with Tags { // symbol not found? --> try to convert implicitly to a type that does have the required // member. Added `| PATTERNmode` to allow enrichment in patterns (so we can add e.g., an // xml member to StringContext, which in turn has an unapply[Seq] method) - if (name != nme.CONSTRUCTOR && mode.inExprModeOr(PATTERNmode)) { + if (name != nme.CONSTRUCTOR && mode.inAny(EXPRmode | PATTERNmode)) { val qual1 = adaptToMemberWithArgs(tree, qual, name, mode, reportAmbiguous = true, saveErrors = true) if ((qual1 ne qual) && !qual1.isErrorTyped) return typed(treeCopy.Select(tree, qual1, name), mode, pt) @@ -4752,44 +4754,41 @@ trait Typers extends Adaptations with Tags { } } - def typedSelectOrSuperCall(tree: Select) = { - val qual = tree.qualifier - val name = tree.name - qual match { - case _: Super if name == nme.CONSTRUCTOR => - val qual1 = - typed(qual, EXPRmode | QUALmode | POLYmode | SUPERCONSTRmode, WildcardType) - // the qualifier type of a supercall constructor is its first parent class - typedSelect(tree, qual1, nme.CONSTRUCTOR) - case _ => - if (Statistics.canEnable) Statistics.incCounter(typedSelectCount) - var qual1 = checkDead(typedQualifier(qual, mode)) - if (name.isTypeName) qual1 = checkStable(qual1) - - val tree1 = // temporarily use `filter` and an alternative for `withFilter` - if (name == nme.withFilter) - silent(_ => typedSelect(tree, qual1, name)) orElse { _ => - silent(_ => typed1(Select(qual1, nme.filter) setPos tree.pos, mode, pt)) match { - case SilentResultValue(result2) => - unit.deprecationWarning( - tree.pos, "`withFilter' method does not yet exist on " + qual1.tpe.widen + - ", using `filter' method instead") - result2 - case SilentTypeError(err) => - WithFilterError(tree, err) - } - } - else - typedSelect(tree, qual1, name) + // temporarily use `filter` as an alternative for `withFilter` + def tryWithFilterAndFilter(tree: Select, qual: Tree): Tree = { + def warn() = unit.deprecationWarning(tree.pos, s"`withFilter' method does not yet exist on ${qual.tpe.widen}, using `filter' method instead") - if (tree.isInstanceOf[PostfixSelect]) - checkFeature(tree.pos, PostfixOpsFeature, name.decode) - if (tree1.symbol != null && tree1.symbol.isOnlyRefinementMember) - checkFeature(tree1.pos, ReflectiveCallsFeature, tree1.symbol.toString) + silent(_ => typedSelect(tree, qual, nme.withFilter)) orElse (_ => + silent(_ => typed1(Select(qual, nme.filter) setPos tree.pos, mode, pt)) match { + case SilentResultValue(res) => warn() ; res + case SilentTypeError(err) => WithFilterError(tree, err) + } + ) + } - if (qual1.hasSymbolWhich(_.isRootPackage)) treeCopy.Ident(tree1, name) - else tree1 - } + def typedSelectOrSuperCall(tree: Select) = tree match { + case Select(qual @ Super(_, _), nme.CONSTRUCTOR) => + typedSelect(tree, typedSelectOrSuperQualifier(qual), nme.CONSTRUCTOR) + case Select(qual, name) => + if (Statistics.canEnable) Statistics.incCounter(typedSelectCount) + val qual1 = checkDead(typedQualifier(qual, mode)) match { + case q if name.isTypeName => checkStable(q) + case q => q + } + val tree1 = name match { + case nme.withFilter => tryWithFilterAndFilter(tree, qual1) + case _ => typedSelect(tree, qual1, name) + } + def sym = tree1.symbol + if (tree.isInstanceOf[PostfixSelect]) + checkFeature(tree.pos, PostfixOpsFeature, name.decode) + if (sym != null && sym.isOnlyRefinementMember) + checkFeature(tree1.pos, ReflectiveCallsFeature, sym.toString) + + qual1.symbol match { + case s: Symbol if s.isRootPackage => treeCopy.Ident(tree1, name) + case _ => tree1 + } } /* A symbol qualifies if: @@ -4962,13 +4961,16 @@ trait Typers extends Adaptations with Tags { } def typedAlternative(alt: Alternative) = { - val alts1 = alt.trees mapConserve (alt => typed(alt, mode | ALTmode, pt)) - treeCopy.Alternative(tree, alts1) setType pt + val saved = context.inPatAlternative + context.inPatAlternative = true + try treeCopy.Alternative(tree, alt.trees mapConserve (alt => typed(alt, mode, pt))) setType pt + finally context.inPatAlternative = saved } def typedStar(tree: Star) = { - if (mode.inNone(STARmode) && !isPastTyper) + if (!context.starPatterns && !isPastTyper) StarPatternWithVarargParametersError(tree) + treeCopy.Star(tree, typed(tree.elem, mode, pt)) setType makeFullyDefined(pt) } @@ -5382,6 +5384,9 @@ trait Typers extends Adaptations with Tags { def typed(tree: Tree, pt: Type): Tree = typed(tree, EXPRmode, pt) + def typed(tree: Tree, mode: Mode): Tree = + typed(tree, mode, WildcardType) + /** Types qualifier `tree` of a select node. * E.g. is tree occurs in a context like `tree.m`. */ @@ -5400,6 +5405,10 @@ trait Typers extends Adaptations with Tags { def typedOperator(tree: Tree): Tree = typed(tree, EXPRmode | FUNmode | POLYmode | TAPPmode, WildcardType) + // the qualifier type of a supercall constructor is its first parent class + private def typedSelectOrSuperQualifier(qual: Tree) = + context withSuperInit typed(qual, EXPRmode | QUALmode | POLYmode) + /** Types a pattern with prototype `pt` */ def typedPattern(tree: Tree, pt: Type): Tree = { // We disable implicits because otherwise some constructs will diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index 7f7bcd70d2..602982337f 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -2,7 +2,6 @@ package scala package tools package reflect -import scala.tools.nsc.EXPRmode import scala.tools.nsc.reporters._ import scala.tools.nsc.CompilerCommand import scala.tools.nsc.io.VirtualDirectory @@ -166,7 +165,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => transformDuringTyper(expr, withImplicitViewsDisabled = withImplicitViewsDisabled, withMacrosDisabled = withMacrosDisabled)( (currentTyper, expr) => { trace("typing (implicit views = %s, macros = %s): ".format(!withImplicitViewsDisabled, !withMacrosDisabled))(showAttributed(expr, true, true, settings.Yshowsymkinds.value)) - currentTyper.silent(_.typed(expr, EXPRmode, pt)) match { + currentTyper.silent(_.typed(expr, pt)) match { case analyzer.SilentResultValue(result) => trace("success: ")(showAttributed(result, true, true, settings.Yshowsymkinds.value)) result diff --git a/src/reflect/scala/reflect/internal/Mode.scala b/src/reflect/scala/reflect/internal/Mode.scala index 05fd5c3337..0cfd802b01 100644 --- a/src/reflect/scala/reflect/internal/Mode.scala +++ b/src/reflect/scala/reflect/internal/Mode.scala @@ -48,11 +48,6 @@ object Mode { */ final val TAPPmode: Mode = 0x080 - /** SUPERCONSTRmode is set for the super - * in a superclass constructor call super.. - */ - final val SUPERCONSTRmode: Mode = 0x100 - /** SNDTRYmode indicates that an application is typed for the 2nd time. * In that case functions may no longer be coerced with implicit views. */ @@ -62,15 +57,6 @@ object Mode { */ final val LHSmode: Mode = 0x400 - /** STARmode is set when star patterns are allowed. - * (This was formerly called REGPATmode.) - */ - final val STARmode: Mode = 0x1000 - - /** ALTmode is set when we are under a pattern alternative. - */ - final val ALTmode: Mode = 0x2000 - /** HKmode is set when we are typing a higher-kinded type. * adapt should then check kind-arity based on the prototypical type's * kind arity. Type arguments should not be inferred. @@ -94,7 +80,7 @@ object Mode { */ final val RETmode: Mode = 0x20000 - final private val StickyModes: Mode = EXPRmode | PATTERNmode | TYPEmode | ALTmode + final private val StickyModes: Mode = EXPRmode | PATTERNmode | TYPEmode /** Translates a mask of mode flags into something readable. */ @@ -107,12 +93,12 @@ object Mode { (1 << 5) -> "POLYmode", (1 << 6) -> "QUALmode", (1 << 7) -> "TAPPmode", - (1 << 8) -> "SUPERCONSTRmode", + (1 << 8) -> "", // formerly SUPERCONSTRmode (1 << 9) -> "SNDTRYmode", (1 << 10) -> "LHSmode", - (1 << 11) -> "", - (1 << 12) -> "STARmode", - (1 << 13) -> "ALTmode", + (1 << 11) -> "", + (1 << 12) -> "", // formerly STARmode + (1 << 13) -> "", // formerly ALTmode (1 << 14) -> "HKmode", (1 << 15) -> "BYVALmode", (1 << 16) -> "TYPEPATmode" @@ -131,40 +117,38 @@ final class Mode private (val bits: Int) extends AnyVal { if (inAny(PATTERNmode | TYPEPATmode)) TYPEmode | TYPEPATmode else TYPEmode - def inAll(required: Mode) = (this & required) == required - def inAny(required: Mode) = (this & required) != NOmode - def inNone(prohibited: Mode) = (this & prohibited) == NOmode - def inAllButNone(required: Mode, prohibited: Mode) = inAll(required) && inNone(prohibited) - def in(allOf: Mode = NOmode, noneOf: Mode = NOmode) = inAll(allOf) && inNone(noneOf) + def inAll(required: Mode) = (this & required) == required + def inAny(required: Mode) = (this & required) != NOmode + def inNone(prohibited: Mode) = (this & prohibited) == NOmode - def inSccMode = inAll(SCCmode) - def inQualMode = inAll(QUALmode) - def inHKMode = inAll(HKmode) + /** True if this mode matches every mode in the 'all' Mode, + * and no modes in the 'none' Mode. + */ + def in(all: Mode = NOmode, none: Mode = NOmode) = inAll(all) && inNone(none) + + def inByValMode = inAll(BYVALmode) + def inExprMode = inAll(EXPRmode) def inFunMode = inAll(FUNmode) - def inPolyMode = inAll(POLYmode) + def inHKMode = inAll(HKmode) + def inLhsMode = inAll(LHSmode) def inPatternMode = inAll(PATTERNmode) - def inExprMode = inAll(EXPRmode) - def inByValMode = inAll(BYVALmode) + def inPolyMode = inAll(POLYmode) + def inQualMode = inAll(QUALmode) def inRetMode = inAll(RETmode) - def inLhsMode = inAll(LHSmode) + def inSccMode = inAll(SCCmode) def inTappMode = inAll(TAPPmode) - def inAltMode = inAll(ALTmode) def inTypeMode = inAll(TYPEmode) def typingTypeByValue = inAll(TYPEmode | BYVALmode) def typingExprByValue = inAll(EXPRmode | BYVALmode) def typingExprFun = inAll(EXPRmode | FUNmode) - def typingExprNotValue = inAllButNone(EXPRmode, BYVALmode) - def typingExprNotLhs = inAllButNone(EXPRmode, LHSmode) - def typingExprNotFun = inAllButNone(EXPRmode, FUNmode) - def typingExprNotFunNotLhs = inAllButNone(EXPRmode, FUNmode | LHSmode) - def typingMonoExprByValue = inAllButNone(EXPRmode | BYVALmode, POLYmode) - - def typingPatternNotFun = inAllButNone(PATTERNmode, FUNmode) def typingPatternFun = inAll(PATTERNmode | FUNmode) - - def inExprModeOr(others: Mode) = inAny(EXPRmode | others) - def inExprModeButNot(prohibited: Mode) = inAllButNone(EXPRmode, prohibited) + def typingExprNotValue = in(all = EXPRmode, none = BYVALmode) + def typingExprNotLhs = in(all = EXPRmode, none = LHSmode) + def typingExprNotFun = in(all = EXPRmode, none = FUNmode) + def typingExprNotFunNotLhs = in(all = EXPRmode, none = FUNmode | LHSmode) + def typingMonoExprByValue = in(all = EXPRmode | BYVALmode, none = POLYmode) + def typingPatternNotFun = in(all = PATTERNmode, none = FUNmode) override def toString = if (bits == 0) "NOmode" -- cgit v1.2.3 From 1c1d45d08f5d303d00e97383722b10f9c9395f4e Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 11 May 2013 13:02:54 -0700 Subject: Eliminated SNDTRYmode. It becomes context mode "SecondTry". --- .../scala/tools/nsc/typechecker/Contexts.scala | 17 ++++++++++++++--- src/compiler/scala/tools/nsc/typechecker/Typers.scala | 19 +++++++++---------- src/reflect/scala/reflect/internal/Mode.scala | 19 +++++++------------ src/reflect/scala/reflect/internal/TreeInfo.scala | 6 +++--- src/reflect/scala/reflect/internal/Types.scala | 5 +++++ 5 files changed, 38 insertions(+), 28 deletions(-) (limited to 'src/compiler/scala') diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 0633c1485f..dc75fa3746 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -241,6 +241,8 @@ trait Contexts { self: Analyzer => def checking = this(Checking) def retyping_=(value: Boolean) = this(ReTyping) = value def retyping = this(ReTyping) + def inSecondTry = this(SecondTry) + def inSecondTry_=(value: Boolean) = this(SecondTry) = value /** These messages are printed when issuing an error */ var diagnostic: List[String] = Nil @@ -357,6 +359,7 @@ trait Contexts { self: Analyzer => def withMacrosDisabled[T](op: => T): T = withMode(disabled = MacrosEnabled)(op) def withStarPatterns[T](op: => T): T = withMode(enabled = StarPatterns)(op) def withSuperInit[T](op: => T): T = withMode(enabled = SuperInit)(op) + def withSecondTry[T](op: => T): T = withMode(enabled = SecondTry)(op) /** @return true if the `expr` evaluates to true within a silent Context that incurs no errors */ @inline final def inSilentMode(expr: => Boolean): Boolean = { @@ -1333,8 +1336,9 @@ object ContextMode { /** Are we in a run of [[scala.tools.nsc.typechecker.TreeCheckers]]? */ final val Checking: ContextMode = 1 << 9 - /** Are we retypechecking arguments independently from the function applied to them? See `Typer.tryTypedApply` */ - // TODO This seems to directly overlap with Mode.SNDTRYmode + /** Are we retypechecking arguments independently from the function applied to them? See `Typer.tryTypedApply` + * TODO - iron out distinction/overlap with SecondTry. + */ final val ReTyping: ContextMode = 1 << 10 /** Are we typechecking pattern alternatives. Formerly ALTmode. */ @@ -1346,6 +1350,11 @@ object ContextMode { /** Are we typing the "super" in a superclass constructor call super.. Formerly SUPERCONSTRmode. */ final val SuperInit: ContextMode = 1 << 13 + /* Is this the second attempt to type this tree? In that case functions + * may no longer be coerced with implicit views. Formerly SNDTRYmode. + */ + final val SecondTry: ContextMode = 1 << 14 + final val DefaultMode: ContextMode = MacrosEnabled private val contextModeNameMap = Map( @@ -1359,7 +1368,9 @@ object ContextMode { Checking -> "Checking", ReTyping -> "ReTyping", PatternAlternative -> "PatternAlternative", - StarPatterns -> "StarPatterns" + StarPatterns -> "StarPatterns", + SuperInit -> "SuperInit", + SecondTry -> "SecondTry" ) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index f80fede3f9..2066ab980d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -34,9 +34,9 @@ trait Typers extends Adaptations with Tags { import TypersStats._ final def forArgMode(fun: Tree, mode: Mode) = - if (treeInfo.isSelfOrSuperConstrCall(fun)) mode | SCCmode - else mode + if (treeInfo.isSelfOrSuperConstrCall(fun)) mode | SCCmode else mode + // printResult(s"forArgMode($fun, $mode) gets SCCmode")(mode | SCCmode) // namer calls typer.computeType(rhs) on DefDef / ValDef when tpt is empty. the result // is cached here and re-used in typedDefDef / typedValDef // Also used to cache imports type-checked by namer. @@ -4450,7 +4450,7 @@ trait Typers extends Adaptations with Tags { else qual if (qual1 ne qual) { val tree1 = Apply(Select(qual1, name) setPos fun.pos, args1) setPos tree.pos - return typed1(tree1, mode | SNDTRYmode, pt) + return context withSecondTry typed1(tree1, mode, pt) } case _ => () } @@ -4496,15 +4496,14 @@ trait Typers extends Adaptations with Tags { if (Statistics.canEnable) Statistics.incCounter(typedApplyCount) val noSecondTry = ( isPastTyper + || context.inSecondTry || (fun2.symbol ne null) && fun2.symbol.isConstructor - || (fun2.tpe match { case mt: MethodType => mt.isImplicit case _ => false }) - ) - val isFirstTry = !noSecondTry && ( - fun2 match { - case Select(_, _) => mode.in(all = EXPRmode, none = SNDTRYmode) - case _ => false - } + || isImplicitMethodType(fun2.tpe) ) + val isFirstTry = fun2 match { + case Select(_, _) => !noSecondTry && mode.inExprMode + case _ => false + } if (isFirstTry) tryTypedApply(fun2, args) else diff --git a/src/reflect/scala/reflect/internal/Mode.scala b/src/reflect/scala/reflect/internal/Mode.scala index 0cfd802b01..89d6be0248 100644 --- a/src/reflect/scala/reflect/internal/Mode.scala +++ b/src/reflect/scala/reflect/internal/Mode.scala @@ -48,11 +48,6 @@ object Mode { */ final val TAPPmode: Mode = 0x080 - /** SNDTRYmode indicates that an application is typed for the 2nd time. - * In that case functions may no longer be coerced with implicit views. - */ - final val SNDTRYmode: Mode = 0x200 - /** LHSmode is set for the left-hand side of an assignment. */ final val LHSmode: Mode = 0x400 @@ -93,12 +88,12 @@ object Mode { (1 << 5) -> "POLYmode", (1 << 6) -> "QUALmode", (1 << 7) -> "TAPPmode", - (1 << 8) -> "", // formerly SUPERCONSTRmode - (1 << 9) -> "SNDTRYmode", + (1 << 8) -> "<>", // formerly SUPERCONSTRmode + (1 << 9) -> "<>", // formerly SNDTRYmode (1 << 10) -> "LHSmode", - (1 << 11) -> "", - (1 << 12) -> "", // formerly STARmode - (1 << 13) -> "", // formerly ALTmode + (1 << 11) -> "<>", + (1 << 12) -> "<>", // formerly STARmode + (1 << 13) -> "<>", // formerly ALTmode (1 << 14) -> "HKmode", (1 << 15) -> "BYVALmode", (1 << 16) -> "TYPEPATmode" @@ -151,6 +146,6 @@ final class Mode private (val bits: Int) extends AnyVal { def typingPatternNotFun = in(all = PATTERNmode, none = FUNmode) override def toString = - if (bits == 0) "NOmode" - else (modeNameMap filterKeys inAll).values.toList.sorted mkString " " + if (this == NOmode) "NOmode" + else (modeNameMap filterKeys inAll).values.toList.sorted mkString "-" } diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 2f1b3208df..58383a2a58 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -203,16 +203,16 @@ abstract class TreeInfo { * same object? */ def isSelfConstrCall(tree: Tree): Boolean = tree match { - case Applied(Ident(nme.CONSTRUCTOR), _, _) => true + case Applied(Ident(nme.CONSTRUCTOR), _, _) => true case Applied(Select(This(_), nme.CONSTRUCTOR), _, _) => true - case _ => false + case _ => false } /** Is tree a super constructor call? */ def isSuperConstrCall(tree: Tree): Boolean = tree match { case Applied(Select(Super(_, _), nme.CONSTRUCTOR), _, _) => true - case _ => false + case _ => false } /** diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 338117e188..eb40733327 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -3964,6 +3964,11 @@ trait Types case _ => false } + def isImplicitMethodType(tp: Type) = tp match { + case mt: MethodType => mt.isImplicit + case _ => false + } + /** This is defined and named as it is because the goal is to exclude source * level types which are not value types (e.g. MethodType) without excluding * necessary internal types such as WildcardType. There are also non-value -- cgit v1.2.3 From b174efbcbcf241903d2dc970f950f594b8c8c5e7 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 11 May 2013 13:02:54 -0700 Subject: Eliminated RETmode. It becomes context mode "ReturnExpr". --- src/compiler/scala/tools/nsc/typechecker/Contexts.scala | 9 +++++++++ src/compiler/scala/tools/nsc/typechecker/Typers.scala | 6 +++--- .../plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala | 4 ++-- src/reflect/scala/reflect/internal/Mode.scala | 5 ----- 4 files changed, 14 insertions(+), 10 deletions(-) (limited to 'src/compiler/scala') diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index dc75fa3746..48df7cb261 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -243,6 +243,7 @@ trait Contexts { self: Analyzer => def retyping = this(ReTyping) def inSecondTry = this(SecondTry) def inSecondTry_=(value: Boolean) = this(SecondTry) = value + def inReturnExpr = this(ReturnExpr) /** These messages are printed when issuing an error */ var diagnostic: List[String] = Nil @@ -361,6 +362,11 @@ trait Contexts { self: Analyzer => def withSuperInit[T](op: => T): T = withMode(enabled = SuperInit)(op) def withSecondTry[T](op: => T): T = withMode(enabled = SecondTry)(op) + def withReturnExpr[T](op: => T): T = { + enclMethod.returnsSeen = true + withMode(enabled = ReturnExpr)(op) + } + /** @return true if the `expr` evaluates to true within a silent Context that incurs no errors */ @inline final def inSilentMode(expr: => Boolean): Boolean = { withMode() { // withMode with no arguments to restore the mode mutated by `setBufferErrors`. @@ -1355,6 +1361,9 @@ object ContextMode { */ final val SecondTry: ContextMode = 1 << 14 + /** Are we in return position? Formerly RETmode. */ + final val ReturnExpr: ContextMode = 1 << 15 + final val DefaultMode: ContextMode = MacrosEnabled private val contextModeNameMap = Map( diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 2066ab980d..3bcc670c89 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -4292,9 +4292,9 @@ trait Typers extends Adaptations with Tags { val DefDef(_, name, _, _, restpt, _) = enclMethod.tree if (restpt.tpe eq null) { ReturnWithoutTypeError(tree, enclMethod.owner) - } else { - context.enclMethod.returnsSeen = true - val expr1: Tree = typed(expr, EXPRmode | BYVALmode | RETmode, restpt.tpe) + } + else { + val expr1 = context withReturnExpr typed(expr, EXPRmode | BYVALmode, restpt.tpe) // Warn about returning a value if no value can be returned. if (restpt.tpe.typeSymbol == UnitClass) { // The typing in expr1 says expr is Unit (it has already been coerced if diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala index 519b90f0c6..e6153596f7 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala @@ -169,7 +169,7 @@ abstract class CPSAnnotationChecker extends CPSUtils { true //} } else false - } else if (!hasPlusMarker(tree.tpe) && annots1.isEmpty && !annots2.isEmpty && mode.inRetMode) { + } else if (!hasPlusMarker(tree.tpe) && annots1.isEmpty && !annots2.isEmpty && typer.context.inReturnExpr) { vprintln("checking enclosing method's result type without annotations") tree.tpe <:< pt.withoutAnnotations } else if (!hasMinusMarker(tree.tpe) && !annots1.isEmpty && mode.inByValMode) { @@ -219,7 +219,7 @@ abstract class CPSAnnotationChecker extends CPSUtils { val res = tree modifyType addMinusMarker vprintln("adapted annotations (by val) of " + tree + " to " + res.tpe) res - } else if (mode.inRetMode && !hasPlusMarker(tree.tpe) && isMissingExpectedAnnots) { + } else if (typer.context.inReturnExpr && !hasPlusMarker(tree.tpe) && isMissingExpectedAnnots) { // add a marker annotation that will make tree.tpe behave as pt, subtyping wise // tree will look like having any possible annotation diff --git a/src/reflect/scala/reflect/internal/Mode.scala b/src/reflect/scala/reflect/internal/Mode.scala index 89d6be0248..a15a3dcc84 100644 --- a/src/reflect/scala/reflect/internal/Mode.scala +++ b/src/reflect/scala/reflect/internal/Mode.scala @@ -71,10 +71,6 @@ object Mode { */ final val TYPEPATmode: Mode = 0x10000 - /** RETmode is set when we are typing a return expression. - */ - final val RETmode: Mode = 0x20000 - final private val StickyModes: Mode = EXPRmode | PATTERNmode | TYPEmode /** Translates a mask of mode flags into something readable. @@ -129,7 +125,6 @@ final class Mode private (val bits: Int) extends AnyVal { def inPatternMode = inAll(PATTERNmode) def inPolyMode = inAll(POLYmode) def inQualMode = inAll(QUALmode) - def inRetMode = inAll(RETmode) def inSccMode = inAll(SCCmode) def inTappMode = inAll(TAPPmode) def inTypeMode = inAll(TYPEmode) -- cgit v1.2.3 From 24cad039b309cf3ccd79aca8f3bae398a42ab66b Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 11 May 2013 13:02:54 -0700 Subject: Eliminated HKmode. It becomes context mode "TypeConstructor". --- .../scala/tools/nsc/typechecker/Contexts.scala | 10 ++- .../scala/tools/nsc/typechecker/RefChecks.scala | 3 +- .../scala/tools/nsc/typechecker/Typers.scala | 75 ++++++++++++---------- src/reflect/scala/reflect/internal/Mode.scala | 9 +-- 4 files changed, 53 insertions(+), 44 deletions(-) (limited to 'src/compiler/scala') diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 48df7cb261..e0b7f8b670 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -244,6 +244,9 @@ trait Contexts { self: Analyzer => def inSecondTry = this(SecondTry) def inSecondTry_=(value: Boolean) = this(SecondTry) = value def inReturnExpr = this(ReturnExpr) + def inTypeConstructor = this(TypeConstructor) + + def defaultModeForTyped: Mode = if (inTypeConstructor) Mode.NOmode else Mode.EXPRmode /** These messages are printed when issuing an error */ var diagnostic: List[String] = Nil @@ -361,6 +364,7 @@ trait Contexts { self: Analyzer => def withStarPatterns[T](op: => T): T = withMode(enabled = StarPatterns)(op) def withSuperInit[T](op: => T): T = withMode(enabled = SuperInit)(op) def withSecondTry[T](op: => T): T = withMode(enabled = SecondTry)(op) + def withTypeConstructor[T](op: => T): T = withMode(enabled = TypeConstructor)(op) def withReturnExpr[T](op: => T): T = { enclMethod.returnsSeen = true @@ -1364,6 +1368,9 @@ object ContextMode { /** Are we in return position? Formerly RETmode. */ final val ReturnExpr: ContextMode = 1 << 15 + /** Are we typing a type constructor? Formerly HKmode. */ + final val TypeConstructor: ContextMode = 1 << 16 + final val DefaultMode: ContextMode = MacrosEnabled private val contextModeNameMap = Map( @@ -1379,7 +1386,8 @@ object ContextMode { PatternAlternative -> "PatternAlternative", StarPatterns -> "StarPatterns", SuperInit -> "SuperInit", - SecondTry -> "SecondTry" + SecondTry -> "SecondTry", + TypeConstructor -> "TypeConstructor" ) } diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 290ad76a1d..0b902318b2 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -944,7 +944,8 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans def checkSensible(pos: Position, fn: Tree, args: List[Tree]) = fn match { case Select(qual, name @ (nme.EQ | nme.NE | nme.eq | nme.ne)) if args.length == 1 => - def isReferenceOp = name == nme.eq || name == nme.ne + // Make sure the 'eq' or 'ne' method is the one in AnyRef. + def isReferenceOp = fn.symbol == Object_eq || fn.symbol == Object_ne def isNew(tree: Tree) = tree match { case Function(_, _) | Apply(Select(New(_), nme.CONSTRUCTOR), _) => true diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 3bcc670c89..f26b15b208 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -877,36 +877,43 @@ trait Typers extends Adaptations with Tags { } def adaptType(): Tree = { - if (mode.inFunMode) { - // todo. the commented line below makes sense for typechecking, say, TypeApply(Ident(`some abstract type symbol`), List(...)) - // because otherwise Ident will have its tpe set to a TypeRef, not to a PolyType, and `typedTypeApply` will fail - // but this needs additional investigation, because it crashes t5228, gadts1 and maybe something else - // tree setType tree.tpe.normalize - tree - } else if (tree.hasSymbolField && !tree.symbol.typeParams.isEmpty && !mode.inHKMode && - !(tree.symbol.isJavaDefined && context.unit.isJava)) { // (7) - // @M When not typing a higher-kinded type ((mode & HKmode) == 0) - // or raw type (tree.symbol.isJavaDefined && context.unit.isJava), types must be of kind *, - // and thus parameterized types must be applied to their type arguments - // @M TODO: why do kind-* tree's have symbols, while higher-kinded ones don't? - MissingTypeParametersError(tree) - } else if ( // (7.1) @M: check kind-arity + // @M When not typing a higher-kinded type (!context.inTypeConstructor) + // or raw type (tree.symbol.isJavaDefined && context.unit.isJava), types must be of kind *, + // and thus parameterized types must be applied to their type arguments + // @M TODO: why do kind-* tree's have symbols, while higher-kinded ones don't? + def kindStarRequired = ( + tree.hasSymbolField + && !context.inTypeConstructor + && !(tree.symbol.isJavaDefined && context.unit.isJava) + ) + // @M: don't check tree.tpe.symbol.typeParams. check tree.tpe.typeParams!!! + // (e.g., m[Int] --> tree.tpe.symbol.typeParams.length == 1, tree.tpe.typeParams.length == 0!) // @M: removed check for tree.hasSymbolField and replace tree.symbol by tree.tpe.symbol // (TypeTree's must also be checked here, and they don't directly have a symbol) - mode.inHKMode && - // @M: don't check tree.tpe.symbol.typeParams. check tree.tpe.typeParams!!! - // (e.g., m[Int] --> tree.tpe.symbol.typeParams.length == 1, tree.tpe.typeParams.length == 0!) - !sameLength(tree.tpe.typeParams, pt.typeParams) && - !(tree.tpe.typeSymbol == AnyClass || - tree.tpe.typeSymbol == NothingClass || - pt == WildcardType)) { - // Check that the actual kind arity (tree.symbol.typeParams.length) conforms to the expected - // kind-arity (pt.typeParams.length). Full checks are done in checkKindBounds in Infer. - // Note that we treat Any and Nothing as kind-polymorphic. - // We can't perform this check when typing type arguments to an overloaded method before the overload is resolved - // (or in the case of an error type) -- this is indicated by pt == WildcardType (see case TypeApply in typed1). + def kindArityMismatch = ( + context.inTypeConstructor + && !sameLength(tree.tpe.typeParams, pt.typeParams) + ) + // Note that we treat Any and Nothing as kind-polymorphic. + // We can't perform this check when typing type arguments to an overloaded method before the overload is resolved + // (or in the case of an error type) -- this is indicated by pt == WildcardType (see case TypeApply in typed1). + def kindArityMismatchOk = tree.tpe.typeSymbol match { + case NothingClass | AnyClass => true + case _ => pt == WildcardType + } + + // todo. It would make sense when mode.inFunMode to instead use + // tree setType tree.tpe.normalize + // when typechecking, say, TypeApply(Ident(`some abstract type symbol`), List(...)) + // because otherwise Ident will have its tpe set to a TypeRef, not to a PolyType, and `typedTypeApply` will fail + // but this needs additional investigation, because it crashes t5228, gadts1 and maybe something else + if (mode.inFunMode) + tree + else if (kindStarRequired && tree.symbol.typeParams.nonEmpty) // (7) + MissingTypeParametersError(tree) + else if (kindArityMismatch && !kindArityMismatchOk) // (7.1) @M: check kind-arity KindArityMismatchError(tree, pt) - } else tree match { // (6) + else tree match { // (6) case TypeTree() => tree case _ => TypeTree(tree.tpe) setOriginal tree } @@ -1028,7 +1035,7 @@ trait Typers extends Adaptations with Tags { } def insertApply(): Tree = { - assert(!mode.inHKMode, mode) //@M + assert(!context.inTypeConstructor, mode) //@M val adapted = adaptToName(tree, nme.apply) def stabilize0(pre: Type): Tree = stabilize(adapted, pre, EXPRmode | QUALmode, WildcardType) @@ -1212,7 +1219,7 @@ trait Typers extends Adaptations with Tags { else if (shouldInsertApply(tree)) insertApply() else if (hasUndetsInMonoMode) { // (9) - assert(!mode.inHKMode, mode) //@M + assert(!context.inTypeConstructor, context) //@M if (mode.typingExprNotFun && pt.typeSymbol == UnitClass) instantiateExpectingUnit(tree, mode) else @@ -1246,7 +1253,7 @@ trait Typers extends Adaptations with Tags { adapt(tree setType arg, mode, pt, original) case tp if mode.typingExprNotLhs && isExistentialType(tp) => adapt(tree setType tp.dealias.skolemizeExistential(context.owner, tree), mode, pt, original) - case PolyType(tparams, restpe) if mode.inNone(TAPPmode | PATTERNmode | HKmode) => // (3) + case PolyType(tparams, restpe) if mode.inNone(TAPPmode | PATTERNmode) && !context.inTypeConstructor => // (3) // assert((mode & HKmode) == 0) //@M a PolyType in HKmode represents an anonymous type function, // we're in HKmode since a higher-kinded type is expected --> hence, don't implicitly apply it to type params! // ticket #2197 triggered turning the assert into a guard @@ -5366,7 +5373,7 @@ trait Typers extends Adaptations with Tags { /** Types expression or definition `tree`. */ def typed(tree: Tree): Tree = { - val ret = typed(tree, EXPRmode, WildcardType) + val ret = typed(tree, context.defaultModeForTyped, WildcardType) ret } @@ -5381,7 +5388,7 @@ trait Typers extends Adaptations with Tags { /** Types expression `tree` with given prototype `pt`. */ def typed(tree: Tree, pt: Type): Tree = - typed(tree, EXPRmode, pt) + typed(tree, context.defaultModeForTyped, pt) def typed(tree: Tree, mode: Mode): Tree = typed(tree, mode, WildcardType) @@ -5444,10 +5451,10 @@ trait Typers extends Adaptations with Tags { /** Types a higher-kinded type tree -- pt denotes the expected kind*/ def typedHigherKindedType(tree: Tree, mode: Mode, pt: Type): Tree = if (pt.typeParams.isEmpty) typedType(tree, mode) // kind is known and it's * - else typed(tree, HKmode, pt) + else context withTypeConstructor typed(tree, NOmode, pt) def typedHigherKindedType(tree: Tree, mode: Mode): Tree = - typed(tree, HKmode, WildcardType) + context withTypeConstructor typed(tree) /** Types a type constructor tree used in a new or supertype */ def typedTypeConstructor(tree: Tree, mode: Mode): Tree = { diff --git a/src/reflect/scala/reflect/internal/Mode.scala b/src/reflect/scala/reflect/internal/Mode.scala index a15a3dcc84..37633c9302 100644 --- a/src/reflect/scala/reflect/internal/Mode.scala +++ b/src/reflect/scala/reflect/internal/Mode.scala @@ -52,12 +52,6 @@ object Mode { */ final val LHSmode: Mode = 0x400 - /** HKmode is set when we are typing a higher-kinded type. - * adapt should then check kind-arity based on the prototypical type's - * kind arity. Type arguments should not be inferred. - */ - final val HKmode: Mode = 0x4000 // @M: could also use POLYmode | TAPPmode - /** BYVALmode is set when we are typing an expression * that occurs in a by-value position. An expression e1 is in by-value * position within expression e2 iff it will be reduced to a value at that @@ -90,7 +84,7 @@ object Mode { (1 << 11) -> "<>", (1 << 12) -> "<>", // formerly STARmode (1 << 13) -> "<>", // formerly ALTmode - (1 << 14) -> "HKmode", + (1 << 14) -> "<>", // formerly HKmode (1 << 15) -> "BYVALmode", (1 << 16) -> "TYPEPATmode" ).map({ case (k, v) => Mode(k) -> v }) @@ -120,7 +114,6 @@ final class Mode private (val bits: Int) extends AnyVal { def inByValMode = inAll(BYVALmode) def inExprMode = inAll(EXPRmode) def inFunMode = inAll(FUNmode) - def inHKMode = inAll(HKmode) def inLhsMode = inAll(LHSmode) def inPatternMode = inAll(PATTERNmode) def inPolyMode = inAll(POLYmode) -- cgit v1.2.3 From 433880e91cba9e1e926e9fcbf04ecd4aeb1d73eb Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 11 May 2013 13:02:54 -0700 Subject: Refactored stabilize. Mode elimination ramps up in difficulty now, so I pursued other forms of code hygiene. --- .../scala/tools/nsc/typechecker/Contexts.scala | 43 ++++-- .../scala/tools/nsc/typechecker/Macros.scala | 8 +- .../scala/tools/nsc/typechecker/Typers.scala | 145 ++++++++++++--------- src/reflect/scala/reflect/internal/Mode.scala | 17 ++- 4 files changed, 128 insertions(+), 85 deletions(-) (limited to 'src/compiler/scala') diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index e0b7f8b670..fc1db32a2d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -356,21 +356,33 @@ trait Contexts { self: Analyzer => finally contextMode = saved } - def withImplicitsEnabled[T](op: => T): T = withMode(enabled = ImplicitsEnabled)(op) - def withImplicitsDisabled[T](op: => T): T = withMode(disabled = ImplicitsEnabled | EnrichmentEnabled)(op) - def withImplicitsDisabledAllowEnrichment[T](op: => T): T = withMode(enabled = EnrichmentEnabled, disabled = ImplicitsEnabled)(op) - def withMacrosEnabled[T](op: => T): T = withMode(enabled = MacrosEnabled)(op) - def withMacrosDisabled[T](op: => T): T = withMode(disabled = MacrosEnabled)(op) - def withStarPatterns[T](op: => T): T = withMode(enabled = StarPatterns)(op) - def withSuperInit[T](op: => T): T = withMode(enabled = SuperInit)(op) - def withSecondTry[T](op: => T): T = withMode(enabled = SecondTry)(op) - def withTypeConstructor[T](op: => T): T = withMode(enabled = TypeConstructor)(op) - - def withReturnExpr[T](op: => T): T = { + @inline final def withImplicitsEnabled[T](op: => T): T = withMode(enabled = ImplicitsEnabled)(op) + @inline final def withImplicitsDisabled[T](op: => T): T = withMode(disabled = ImplicitsEnabled | EnrichmentEnabled)(op) + @inline final def withImplicitsDisabledAllowEnrichment[T](op: => T): T = withMode(enabled = EnrichmentEnabled, disabled = ImplicitsEnabled)(op) + @inline final def withMacrosEnabled[T](op: => T): T = withMode(enabled = MacrosEnabled)(op) + @inline final def withMacrosDisabled[T](op: => T): T = withMode(disabled = MacrosEnabled)(op) + @inline final def withinStarPatterns[T](op: => T): T = withMode(enabled = StarPatterns)(op) + @inline final def withinSuperInit[T](op: => T): T = withMode(enabled = SuperInit)(op) + @inline final def withinSecondTry[T](op: => T): T = withMode(enabled = SecondTry)(op) + @inline final def withinTypeConstructor[T](op: => T): T = withMode(enabled = TypeConstructor)(op) + + /* TODO - consolidate returnsSeen (which seems only to be used by checkDead) + * and ReturnExpr. + */ + @inline final def withinReturnExpr[T](op: => T): T = { enclMethod.returnsSeen = true withMode(enabled = ReturnExpr)(op) } + /** TODO: The "sticky modes" are EXPRmode, PATTERNmode, TYPEmode. + * To mimick the sticky mode behavior, when captain stickyfingers + * comes around we need to propagate those modes but forget the other + * context modes which were once mode bits; those being so far the + * ones listed here. + */ + @inline final def withOnlyStickyModes[T](op: => T): T = + withMode(disabled = PatternAlternative | StarPatterns | SuperInit | SecondTry | ReturnExpr | TypeConstructor | TypeApplication)(op) + /** @return true if the `expr` evaluates to true within a silent Context that incurs no errors */ @inline final def inSilentMode(expr: => Boolean): Boolean = { withMode() { // withMode with no arguments to restore the mode mutated by `setBufferErrors`. @@ -1371,6 +1383,12 @@ object ContextMode { /** Are we typing a type constructor? Formerly HKmode. */ final val TypeConstructor: ContextMode = 1 << 16 + /** Are we in the function/type constructor part of a type application? + * When we are, we do not decompose PolyTypes. Formerly TAPPmode. + * TODO. + */ + final val TypeApplication: ContextMode = 1 << 17 + final val DefaultMode: ContextMode = MacrosEnabled private val contextModeNameMap = Map( @@ -1387,7 +1405,8 @@ object ContextMode { StarPatterns -> "StarPatterns", SuperInit -> "SuperInit", SecondTry -> "SecondTry", - TypeConstructor -> "TypeConstructor" + TypeConstructor -> "TypeConstructor", + TypeApplication -> "TypeApplication" ) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index d07297bb35..31cc8bd93c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -362,6 +362,8 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { catch { case MacroBodyTypecheckException => EmptyTree } class MacroTyper(val typer: Typer, val macroDdef: DefDef) extends MacroErrors { + private def typed1Expr(tree: Tree) = typer.typed1(tree, EXPRmode, WildcardType) + // Phase I: sanity checks val macroDef = macroDdef.symbol macroLogVerbose("typechecking macro def %s at %s".format(macroDef, macroDdef.pos)) @@ -379,20 +381,20 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { // e.g. a "type arguments [U] do not conform to method foo's type parameter bounds" error // doesn't manifest itself as an error in the resulting tree val prevNumErrors = reporter.ERROR.count - var rhs1 = typer.typed1(rhs, EXPRmode, WildcardType) + var rhs1 = typed1Expr(rhs) def rhsNeedsMacroExpansion = rhs1.symbol != null && rhs1.symbol.isMacro && !rhs1.symbol.isErroneous while (rhsNeedsMacroExpansion) { rhs1 = macroExpand1(typer, rhs1) match { case Success(expanded) => try { - val typechecked = typer.typed1(expanded, EXPRmode, WildcardType) + val typechecked = typed1Expr(expanded) macroLogVerbose("typechecked1:%n%s%n%s".format(typechecked, showRaw(typechecked))) typechecked } finally { popMacroContext() } case Fallback(fallback) => - typer.typed1(fallback, EXPRmode, WildcardType) + typed1Expr(fallback) case Delayed(delayed) => delayed case Skipped(skipped) => diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index f26b15b208..eeae7da94f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -592,45 +592,56 @@ trait Typers extends Adaptations with Tags { /** Post-process an identifier or selection node, performing the following: * 1. Check that non-function pattern expressions are stable + * (and narrow the type of modules: a module reference in a pattern has type Foo.type, not "object Foo") * 2. Check that packages and static modules are not used as values * 3. Turn tree type into stable type if possible and required by context. * 4. Give getClass calls a more precise type based on the type of the target of the call. */ private def stabilize(tree: Tree, pre: Type, mode: Mode, pt: Type): Tree = { + // Side effect time! Don't be an idiot like me and think you + // can move "val sym = tree.symbol" before this line, because + // inferExprAlternative side-effects the tree's symbol. if (tree.symbol.isOverloaded && !mode.inFunMode) inferExprAlternative(tree, pt) val sym = tree.symbol - def fail() = NotAValueError(tree, sym) + val isStableIdPattern = mode.typingPatternNotFun && tree.isTerm - if (tree.isErrorTyped) tree - else if (mode.typingPatternNotFun && tree.isTerm) { // (1) - if (sym.isValue) { - val tree1 = checkStable(tree) - // A module reference in a pattern has type Foo.type, not "object Foo" - if (sym.isModuleNotMethod) tree1 setType singleType(pre, sym) - else tree1 - } - else fail() - } else if (mode.in(all = EXPRmode, none = QUALmode) && !sym.isValue && !phase.erasedTypes) { // (2) - fail() - } else { - if (sym.isStable && pre.isStable && !isByNameParamType(tree.tpe) && - (isStableContext(tree, mode, pt) || sym.isModuleNotMethod)) - tree.setType(singleType(pre, sym)) - // To fully benefit from special casing the return type of - // getClass, we have to catch it immediately so expressions - // like x.getClass().newInstance() are typed with the type of x. - else if ( tree.symbol.name == nme.getClass_ - && tree.tpe.params.isEmpty - // TODO: If the type of the qualifier is inaccessible, we can cause private types - // to escape scope here, e.g. pos/t1107. I'm not sure how to properly handle this - // so for now it requires the type symbol be public. - && pre.typeSymbol.isPublic) - tree setType MethodType(Nil, getClassReturnType(pre)) - else - tree - } + def isModuleTypedExpr = ( + sym.isStable + && pre.isStable + && !isByNameParamType(tree.tpe) + && (isStableContext(tree, mode, pt) || sym.isModuleNotMethod) + ) + def isStableValueRequired = ( + isStableIdPattern + || mode.in(all = EXPRmode, none = QUALmode) && !phase.erasedTypes + ) + // To fully benefit from special casing the return type of + // getClass, we have to catch it immediately so expressions like + // x.getClass().newInstance() are typed with the type of x. TODO: If the + // type of the qualifier is inaccessible, we can cause private types to + // escape scope here, e.g. pos/t1107. I'm not sure how to properly handle + // this so for now it requires the type symbol be public. + def isGetClassCall = ( + (sym == Any_getClass || sym == Object_getClass) + && pre.typeSymbol.isPublic + ) + def narrowIf(tree: Tree, condition: Boolean) = + if (condition) tree setType singleType(pre, sym) else tree + + if (tree.isErrorTyped) + tree + else if (!sym.isValue && isStableValueRequired) // (2) + NotAValueError(tree, sym) + else if (isStableIdPattern) // (1) + narrowIf(checkStable(tree), sym.isModuleNotMethod) + else if (isModuleTypedExpr) // (3) + narrowIf(tree, true) + else if (isGetClassCall) // (4) + tree setType MethodType(Nil, getClassReturnType(pre)) + else + tree } private def isNarrowable(tpe: Type): Boolean = unwrapWrapperTypes(tpe) match { @@ -642,12 +653,17 @@ trait Typers extends Adaptations with Tags { val sym = tree.symbol val pre = tree match { case Select(qual, _) => qual.tpe - case _ => NoPrefix + case _ => NoPrefix + } + def stabilizable = ( + pre.isStable + && sym.tpe.params.isEmpty + && (isStableContext(tree, mode, pt) || sym.isModule) + ) + tree.tpe match { + case MethodType(_, _) if stabilizable => tree setType MethodType(Nil, singleType(pre, sym)) // TODO: should this be a NullaryMethodType? + case _ => tree } - if (tree.tpe.isInstanceOf[MethodType] && pre.isStable && sym.tpe.params.isEmpty && - (isStableContext(tree, mode, pt) || sym.isModule)) - tree.setType(MethodType(List(), singleType(pre, sym))) // TODO: should this be a NullaryMethodType? - else tree } /** The member with given name of given qualifier tree */ @@ -834,7 +850,7 @@ trait Typers extends Adaptations with Tags { } orElse { _ => debuglog("fallback on implicits: " + tree + "/" + resetAllAttrs(original)) - val tree1 = typed(resetAllAttrs(original), mode, WildcardType) + val tree1 = typed(resetAllAttrs(original), mode) // Q: `typed` already calls `pluginsTyped` and `adapt`. the only difference here is that // we pass `EmptyTree` as the `original`. intended? added in 2009 (53d98e7d42) by martin. tree1 setType pluginsTyped(tree1.tpe, this, tree1, mode, pt) @@ -864,7 +880,7 @@ trait Typers extends Adaptations with Tags { // (note that (3) does not call typed to do the polymorphic type instantiation -- // it is called after the tree has been typed with a polymorphic expected result type) if (hasUndets) - instantiate(typed(tree0, mode, WildcardType), mode, pt) + instantiate(typed(tree0, mode), mode, pt) else typed(tree0, mode, pt) } @@ -1037,7 +1053,7 @@ trait Typers extends Adaptations with Tags { def insertApply(): Tree = { assert(!context.inTypeConstructor, mode) //@M val adapted = adaptToName(tree, nme.apply) - def stabilize0(pre: Type): Tree = stabilize(adapted, pre, EXPRmode | QUALmode, WildcardType) + def stabilize0(pre: Type): Tree = stabilize(adapted, pre, MonoQualifierModes, WildcardType) // TODO reconcile the overlap between Typers#stablize and TreeGen.stabilize val qual = adapted match { @@ -1199,11 +1215,14 @@ trait Typers extends Adaptations with Tags { def vanillaAdapt(tree: Tree) = { def applyPossible = { def applyMeth = member(adaptToName(tree, nme.apply), nme.apply) + def hasPolymorphicApply = applyMeth.alternatives exists (_.tpe.typeParams.nonEmpty) + def hasMonomorphicApply = applyMeth.alternatives exists (_.tpe.paramSectionCount > 0) + dyna.acceptsApplyDynamic(tree.tpe) || ( if (mode.inTappMode) - tree.tpe.typeParams.isEmpty && applyMeth.filter(!_.tpe.typeParams.isEmpty) != NoSymbol + tree.tpe.typeParams.isEmpty && hasPolymorphicApply else - applyMeth.filter(_.tpe.paramSectionCount > 0) != NoSymbol + hasMonomorphicApply ) } def shouldInsertApply(tree: Tree) = mode.typingExprFun && { @@ -3020,7 +3039,7 @@ trait Typers extends Adaptations with Tags { } def typedArg(arg: Tree, mode: Mode, newmode: Mode, pt: Type): Tree = { - val typedMode = mode.onlySticky | newmode + val typedMode = mode stickyPlus newmode val t = withCondConstrTyper(mode.inSccMode)(_.typed(arg, typedMode, pt)) checkDead.inMode(typedMode, t) } @@ -3037,16 +3056,15 @@ trait Typers extends Adaptations with Tags { * (docs reverse-engineered -- AM) */ def typedArgs(args0: List[Tree], mode: Mode, formals0: List[Type], adapted0: List[Type]): List[Tree] = { - val sticky = mode.onlySticky def loop(args: List[Tree], formals: List[Type], adapted: List[Type]): List[Tree] = { if (args.isEmpty || adapted.isEmpty) Nil else { // No formals left or * indicates varargs. val isVarArgs = formals.isEmpty || formals.tail.isEmpty && isRepeatedParamType(formals.head) val isByName = formals.nonEmpty && isByNameParamType(formals.head) - def typedMode = if (isByName) sticky else sticky | BYVALmode + def typedMode = mode stickyPlus ( if (isByName) NOmode else BYVALmode ) def body = typedArg(args.head, mode, typedMode, adapted.head) - def arg1 = if (isVarArgs) context.withStarPatterns(body) else body + def arg1 = if (isVarArgs) context.withinStarPatterns(body) else body // formals may be empty, so don't call tail arg1 :: loop(args.tail, formals drop 1, adapted.tail) @@ -4301,7 +4319,7 @@ trait Typers extends Adaptations with Tags { ReturnWithoutTypeError(tree, enclMethod.owner) } else { - val expr1 = context withReturnExpr typed(expr, EXPRmode | BYVALmode, restpt.tpe) + val expr1 = context withinReturnExpr typedExprByValue(expr, restpt.tpe) // Warn about returning a value if no value can be returned. if (restpt.tpe.typeSymbol == UnitClass) { // The typing in expr1 says expr is Unit (it has already been coerced if @@ -4457,7 +4475,7 @@ trait Typers extends Adaptations with Tags { else qual if (qual1 ne qual) { val tree1 = Apply(Select(qual1, name) setPos fun.pos, args1) setPos tree.pos - return context withSecondTry typed1(tree1, mode, pt) + return context withinSecondTry typed1(tree1, mode, pt) } case _ => () } @@ -4829,7 +4847,7 @@ trait Typers extends Adaptations with Tags { setError(tree) } // ignore current variable scope in patterns to enforce linearity - val startContext = if (mode.inNone(PATTERNmode | TYPEPATmode)) context else context.outer + val startContext = if (mode.typingPatternOrTypePat) context.outer else context val nameLookup = tree.symbol match { case NoSymbol => startContext.lookupSymbol(name, qualifies) case sym => LookupSucceeded(EmptyTree, sym) @@ -5056,7 +5074,7 @@ trait Typers extends Adaptations with Tags { } case t if treeInfo isWildcardStarType t => - val exprTyped = typed(expr, mode.onlySticky, WildcardType) + val exprTyped = typed(expr, mode.onlySticky) def subArrayType(pt: Type) = if (isPrimitiveValueClass(pt.typeSymbol) || !isFullyDefined(pt)) arrayType(pt) else { @@ -5066,7 +5084,7 @@ trait Typers extends Adaptations with Tags { val (exprAdapted, baseClass) = exprTyped.tpe.typeSymbol match { case ArrayClass => (adapt(exprTyped, mode.onlySticky, subArrayType(pt)), ArrayClass) - case _ => (adapt(exprTyped, mode.onlySticky, seqType(pt)), SeqClass) + case _ => (adapt(exprTyped, mode.onlySticky, seqType(pt)), SeqClass) } exprAdapted.tpe.baseType(baseClass) match { case TypeRef(_, _, List(elemtp)) => @@ -5108,7 +5126,7 @@ trait Typers extends Adaptations with Tags { //val undets = context.undetparams // @M: fun is typed in TAPPmode because it is being applied to its actual type parameters - val fun1 = typed(fun, mode.forFunMode | TAPPmode, WildcardType) + val fun1 = typed(fun, mode.forFunMode | TAPPmode) val tparams = fun1.symbol.typeParams //@M TODO: val undets_fun = context.undetparams ? @@ -5190,7 +5208,7 @@ trait Typers extends Adaptations with Tags { def typedSingletonTypeTree(tree: SingletonTypeTree) = { val ref1 = checkStable( context.withImplicitsDisabled( - typed(tree.ref, EXPRmode | QUALmode | (mode & TYPEPATmode), AnyRefClass.tpe) + typed(tree.ref, MonoQualifierModes | mode.onlyTypePat, AnyRefClass.tpe) ) ) tree setType ref1.tpe.resultType @@ -5397,7 +5415,7 @@ trait Typers extends Adaptations with Tags { * E.g. is tree occurs in a context like `tree.m`. */ def typedQualifier(tree: Tree, mode: Mode, pt: Type): Tree = - typed(tree, EXPRmode | QUALmode | POLYmode | mode & TYPEPATmode, pt) // TR: don't set BYVALmode, since qualifier might end up as by-name param to an implicit + typed(tree, PolyQualifierModes | mode.onlyTypePat, pt) // TR: don't set BYVALmode, since qualifier might end up as by-name param to an implicit /** Types qualifier `tree` of a select node. * E.g. is tree occurs in a context like `tree.m`. @@ -5408,12 +5426,11 @@ trait Typers extends Adaptations with Tags { def typedQualifier(tree: Tree): Tree = typedQualifier(tree, NOmode, WildcardType) /** Types function part of an application */ - def typedOperator(tree: Tree): Tree = - typed(tree, EXPRmode | FUNmode | POLYmode | TAPPmode, WildcardType) + def typedOperator(tree: Tree): Tree = typed(tree, OperatorModes) // the qualifier type of a supercall constructor is its first parent class private def typedSelectOrSuperQualifier(qual: Tree) = - context withSuperInit typed(qual, EXPRmode | QUALmode | POLYmode) + context withinSuperInit typed(qual, PolyQualifierModes) /** Types a pattern with prototype `pt` */ def typedPattern(tree: Tree, pt: Type): Tree = { @@ -5437,7 +5454,7 @@ trait Typers extends Adaptations with Tags { // TODO: can we achieve the pattern matching bit of the string interpolation SIP without this? typingInPattern(context.withImplicitsDisabledAllowEnrichment(typed(tree, PATTERNmode, pt))) match { case tpt if tpt.isType => PatternMustBeValue(tpt, pt); tpt - case pat => pat + case pat => pat } } @@ -5451,10 +5468,10 @@ trait Typers extends Adaptations with Tags { /** Types a higher-kinded type tree -- pt denotes the expected kind*/ def typedHigherKindedType(tree: Tree, mode: Mode, pt: Type): Tree = if (pt.typeParams.isEmpty) typedType(tree, mode) // kind is known and it's * - else context withTypeConstructor typed(tree, NOmode, pt) + else context withinTypeConstructor typed(tree, NOmode, pt) def typedHigherKindedType(tree: Tree, mode: Mode): Tree = - context withTypeConstructor typed(tree) + context withinTypeConstructor typed(tree) /** Types a type constructor tree used in a new or supertype */ def typedTypeConstructor(tree: Tree, mode: Mode): Tree = { @@ -5510,17 +5527,17 @@ trait Typers extends Adaptations with Tags { if (isMacroBodyOkay && shouldInheritMacroImplReturnType) computeMacroDefTypeFromMacroImpl(ddef, tree1.symbol) else AnyClass.tpe } - def transformedOr(tree: Tree, op: => Tree): Tree = transformed.get(tree) match { - case Some(tree1) => transformed -= tree; tree1 - case None => op + def transformedOr(tree: Tree, op: => Tree): Tree = transformed remove tree match { + case Some(tree1) => tree1 + case _ => op } - def transformedOrTyped(tree: Tree, mode: Mode, pt: Type): Tree = transformed.get(tree) match { - case Some(tree1) => transformed -= tree; tree1 - case None => typed(tree, mode, pt) - } + def transformedOrTyped(tree: Tree, mode: Mode, pt: Type): Tree = transformed remove tree match { + case Some(tree1) => tree1 + case _ => typed(tree, mode, pt) } } +} object TypersStats { import scala.reflect.internal.TypesStats._ diff --git a/src/reflect/scala/reflect/internal/Mode.scala b/src/reflect/scala/reflect/internal/Mode.scala index 37633c9302..8b94431821 100644 --- a/src/reflect/scala/reflect/internal/Mode.scala +++ b/src/reflect/scala/reflect/internal/Mode.scala @@ -67,6 +67,10 @@ object Mode { final private val StickyModes: Mode = EXPRmode | PATTERNmode | TYPEmode + final val MonoQualifierModes: Mode = EXPRmode | QUALmode + final val PolyQualifierModes: Mode = EXPRmode | QUALmode | POLYmode + final val OperatorModes: Mode = EXPRmode | POLYmode | TAPPmode | FUNmode + /** Translates a mask of mode flags into something readable. */ private val modeNameMap = Map[Int, String]( // TODO why duplicate the bitmasks here, rather than just referring to this.EXPRmode etc? @@ -96,11 +100,12 @@ final class Mode private (val bits: Int) extends AnyVal { def |(other: Mode): Mode = new Mode(bits | other.bits) def &~(other: Mode): Mode = new Mode(bits & ~(other.bits)) - def onlySticky = this & Mode.StickyModes - def forFunMode = this & (Mode.StickyModes | SCCmode) | FUNmode | POLYmode | BYVALmode - def forTypeMode = - if (inAny(PATTERNmode | TYPEPATmode)) TYPEmode | TYPEPATmode - else TYPEmode + def onlyTypePat = this & TYPEPATmode + + def stickyPlus(mode: Mode) = onlySticky | mode + def onlySticky = this & Mode.StickyModes + def forFunMode = this & (Mode.StickyModes | SCCmode) | FUNmode | POLYmode | BYVALmode + def forTypeMode = if (typingPatternOrTypePat) TYPEmode | TYPEPATmode else TYPEmode def inAll(required: Mode) = (this & required) == required def inAny(required: Mode) = (this & required) != NOmode @@ -114,7 +119,6 @@ final class Mode private (val bits: Int) extends AnyVal { def inByValMode = inAll(BYVALmode) def inExprMode = inAll(EXPRmode) def inFunMode = inAll(FUNmode) - def inLhsMode = inAll(LHSmode) def inPatternMode = inAll(PATTERNmode) def inPolyMode = inAll(POLYmode) def inQualMode = inAll(QUALmode) @@ -122,6 +126,7 @@ final class Mode private (val bits: Int) extends AnyVal { def inTappMode = inAll(TAPPmode) def inTypeMode = inAll(TYPEmode) + def typingPatternOrTypePat = inAny(PATTERNmode | TYPEPATmode) def typingTypeByValue = inAll(TYPEmode | BYVALmode) def typingExprByValue = inAll(EXPRmode | BYVALmode) def typingExprFun = inAll(EXPRmode | FUNmode) -- cgit v1.2.3 From c663ecf8677eda3fe8c91170b614eb7166b18711 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 11 May 2013 13:02:54 -0700 Subject: Incorporated reviewer feedback. Made things a little more consistent and self-apparent. --- .../scala/tools/nsc/typechecker/Contexts.scala | 21 ++++++++------ .../scala/tools/nsc/typechecker/Typers.scala | 16 +++++------ src/reflect/scala/reflect/internal/Mode.scala | 32 ++++++++++------------ 3 files changed, 35 insertions(+), 34 deletions(-) (limited to 'src/compiler/scala') diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index fc1db32a2d..21c33aad0d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -365,6 +365,7 @@ trait Contexts { self: Analyzer => @inline final def withinSuperInit[T](op: => T): T = withMode(enabled = SuperInit)(op) @inline final def withinSecondTry[T](op: => T): T = withMode(enabled = SecondTry)(op) @inline final def withinTypeConstructor[T](op: => T): T = withMode(enabled = TypeConstructor)(op) + @inline final def withinPatAlternative[T](op: => T): T = withMode(enabled = PatternAlternative)(op) /* TODO - consolidate returnsSeen (which seems only to be used by checkDead) * and ReturnExpr. @@ -374,14 +375,8 @@ trait Contexts { self: Analyzer => withMode(enabled = ReturnExpr)(op) } - /** TODO: The "sticky modes" are EXPRmode, PATTERNmode, TYPEmode. - * To mimick the sticky mode behavior, when captain stickyfingers - * comes around we need to propagate those modes but forget the other - * context modes which were once mode bits; those being so far the - * ones listed here. - */ - @inline final def withOnlyStickyModes[T](op: => T): T = - withMode(disabled = PatternAlternative | StarPatterns | SuperInit | SecondTry | ReturnExpr | TypeConstructor | TypeApplication)(op) + // See comment on FormerNonStickyModes. + @inline final def withOnlyStickyModes[T](op: => T): T = withMode(disabled = FormerNonStickyModes)(op) /** @return true if the `expr` evaluates to true within a silent Context that incurs no errors */ @inline final def inSilentMode(expr: => Boolean): Boolean = { @@ -1389,6 +1384,16 @@ object ContextMode { */ final val TypeApplication: ContextMode = 1 << 17 + /** TODO: The "sticky modes" are EXPRmode, PATTERNmode, TYPEmode. + * To mimick the sticky mode behavior, when captain stickyfingers + * comes around we need to propagate those modes but forget the other + * context modes which were once mode bits; those being so far the + * ones listed here. + */ + final val FormerNonStickyModes: ContextMode = ( + PatternAlternative | StarPatterns | SuperInit | SecondTry | ReturnExpr | TypeConstructor | TypeApplication + ) + final val DefaultMode: ContextMode = MacrosEnabled private val contextModeNameMap = Map( diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index eeae7da94f..5cce4865cc 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3039,7 +3039,7 @@ trait Typers extends Adaptations with Tags { } def typedArg(arg: Tree, mode: Mode, newmode: Mode, pt: Type): Tree = { - val typedMode = mode stickyPlus newmode + val typedMode = mode.onlySticky | newmode val t = withCondConstrTyper(mode.inSccMode)(_.typed(arg, typedMode, pt)) checkDead.inMode(typedMode, t) } @@ -3062,7 +3062,7 @@ trait Typers extends Adaptations with Tags { // No formals left or * indicates varargs. val isVarArgs = formals.isEmpty || formals.tail.isEmpty && isRepeatedParamType(formals.head) val isByName = formals.nonEmpty && isByNameParamType(formals.head) - def typedMode = mode stickyPlus ( if (isByName) NOmode else BYVALmode ) + def typedMode = if (isByName) mode.onlySticky else mode.onlySticky | BYVALmode def body = typedArg(args.head, mode, typedMode, adapted.head) def arg1 = if (isVarArgs) context.withinStarPatterns(body) else body @@ -4984,13 +4984,11 @@ trait Typers extends Adaptations with Tags { newTyper(context.makeNewScope(ddef, sym)).constrTyperIf(isConstrDefaultGetter) } - def typedAlternative(alt: Alternative) = { - val saved = context.inPatAlternative - context.inPatAlternative = true - try treeCopy.Alternative(tree, alt.trees mapConserve (alt => typed(alt, mode, pt))) setType pt - finally context.inPatAlternative = saved - } - + def typedAlternative(alt: Alternative) = ( + context withinPatAlternative ( + treeCopy.Alternative(tree, alt.trees mapConserve (alt => typed(alt, mode, pt))) setType pt + ) + ) def typedStar(tree: Star) = { if (!context.starPatterns && !isPastTyper) StarPatternWithVarargParametersError(tree) diff --git a/src/reflect/scala/reflect/internal/Mode.scala b/src/reflect/scala/reflect/internal/Mode.scala index 8b94431821..7a7c6c8c76 100644 --- a/src/reflect/scala/reflect/internal/Mode.scala +++ b/src/reflect/scala/reflect/internal/Mode.scala @@ -65,11 +65,11 @@ object Mode { */ final val TYPEPATmode: Mode = 0x10000 - final private val StickyModes: Mode = EXPRmode | PATTERNmode | TYPEmode - - final val MonoQualifierModes: Mode = EXPRmode | QUALmode - final val PolyQualifierModes: Mode = EXPRmode | QUALmode | POLYmode - final val OperatorModes: Mode = EXPRmode | POLYmode | TAPPmode | FUNmode + private val StickyModes: Mode = EXPRmode | PATTERNmode | TYPEmode + private val StickyModesForFun: Mode = StickyModes | SCCmode + final val MonoQualifierModes: Mode = EXPRmode | QUALmode + final val PolyQualifierModes: Mode = EXPRmode | QUALmode | POLYmode + final val OperatorModes: Mode = EXPRmode | POLYmode | TAPPmode | FUNmode /** Translates a mask of mode flags into something readable. */ @@ -96,16 +96,14 @@ object Mode { import Mode._ final class Mode private (val bits: Int) extends AnyVal { - def &(other: Mode): Mode = new Mode(bits & other.bits) - def |(other: Mode): Mode = new Mode(bits | other.bits) + def &(other: Mode): Mode = new Mode(bits & other.bits) + def |(other: Mode): Mode = new Mode(bits | other.bits) def &~(other: Mode): Mode = new Mode(bits & ~(other.bits)) def onlyTypePat = this & TYPEPATmode - - def stickyPlus(mode: Mode) = onlySticky | mode - def onlySticky = this & Mode.StickyModes - def forFunMode = this & (Mode.StickyModes | SCCmode) | FUNmode | POLYmode | BYVALmode - def forTypeMode = if (typingPatternOrTypePat) TYPEmode | TYPEPATmode else TYPEmode + def onlySticky = this & Mode.StickyModes + def forFunMode = this & Mode.StickyModesForFun | FUNmode | POLYmode | BYVALmode + def forTypeMode = if (typingPatternOrTypePat) TYPEmode | TYPEPATmode else TYPEmode def inAll(required: Mode) = (this & required) == required def inAny(required: Mode) = (this & required) != NOmode @@ -126,17 +124,17 @@ final class Mode private (val bits: Int) extends AnyVal { def inTappMode = inAll(TAPPmode) def inTypeMode = inAll(TYPEmode) - def typingPatternOrTypePat = inAny(PATTERNmode | TYPEPATmode) - def typingTypeByValue = inAll(TYPEmode | BYVALmode) def typingExprByValue = inAll(EXPRmode | BYVALmode) def typingExprFun = inAll(EXPRmode | FUNmode) - def typingPatternFun = inAll(PATTERNmode | FUNmode) - def typingExprNotValue = in(all = EXPRmode, none = BYVALmode) - def typingExprNotLhs = in(all = EXPRmode, none = LHSmode) def typingExprNotFun = in(all = EXPRmode, none = FUNmode) def typingExprNotFunNotLhs = in(all = EXPRmode, none = FUNmode | LHSmode) + def typingExprNotLhs = in(all = EXPRmode, none = LHSmode) + def typingExprNotValue = in(all = EXPRmode, none = BYVALmode) def typingMonoExprByValue = in(all = EXPRmode | BYVALmode, none = POLYmode) + def typingPatternFun = inAll(PATTERNmode | FUNmode) def typingPatternNotFun = in(all = PATTERNmode, none = FUNmode) + def typingPatternOrTypePat = inAny(PATTERNmode | TYPEPATmode) + def typingTypeByValue = inAll(TYPEmode | BYVALmode) override def toString = if (this == NOmode) "NOmode" -- cgit v1.2.3 From d93826f278b2ee8be3c4092bf800c2156d35d692 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Thu, 16 May 2013 16:53:49 -0700 Subject: Incorporated reviewer feedback. Made things a little more consistent and self-apparent. --- .../scala/tools/nsc/typechecker/Contexts.scala | 52 +++++++++++----------- .../scala/tools/nsc/typechecker/Duplicators.scala | 2 +- .../scala/tools/nsc/typechecker/Typers.scala | 46 +++++++++---------- src/reflect/scala/reflect/internal/Mode.scala | 22 ++++----- 4 files changed, 60 insertions(+), 62 deletions(-) (limited to 'src/compiler/scala') diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 9794497667..61967d4cee 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -244,9 +244,9 @@ trait Contexts { self: Analyzer => def inSecondTry = this(SecondTry) def inSecondTry_=(value: Boolean) = this(SecondTry) = value def inReturnExpr = this(ReturnExpr) - def inTypeConstructor = this(TypeConstructor) + def inTypeConstructorAllowed = this(TypeConstructorAllowed) - def defaultModeForTyped: Mode = if (inTypeConstructor) Mode.NOmode else Mode.EXPRmode + def defaultModeForTyped: Mode = if (inTypeConstructorAllowed) Mode.NOmode else Mode.EXPRmode /** These messages are printed when issuing an error */ var diagnostic: List[String] = Nil @@ -364,9 +364,14 @@ trait Contexts { self: Analyzer => @inline final def withinStarPatterns[T](op: => T): T = withMode(enabled = StarPatterns)(op) @inline final def withinSuperInit[T](op: => T): T = withMode(enabled = SuperInit)(op) @inline final def withinSecondTry[T](op: => T): T = withMode(enabled = SecondTry)(op) - @inline final def withinTypeConstructor[T](op: => T): T = withMode(enabled = TypeConstructor)(op) @inline final def withinPatAlternative[T](op: => T): T = withMode(enabled = PatternAlternative)(op) + /** TypeConstructorAllowed is enabled when we are typing a higher-kinded type. + * adapt should then check kind-arity based on the prototypical type's kind + * arity. Type arguments should not be inferred. + */ + @inline final def withinTypeConstructorAllowed[T](op: => T): T = withMode(enabled = TypeConstructorAllowed)(op) + /* TODO - consolidate returnsSeen (which seems only to be used by checkDead) * and ReturnExpr. */ @@ -1375,14 +1380,8 @@ object ContextMode { /** Are we in return position? Formerly RETmode. */ final val ReturnExpr: ContextMode = 1 << 15 - /** Are we typing a type constructor? Formerly HKmode. */ - final val TypeConstructor: ContextMode = 1 << 16 - - /** Are we in the function/type constructor part of a type application? - * When we are, we do not decompose PolyTypes. Formerly TAPPmode. - * TODO. - */ - final val TypeApplication: ContextMode = 1 << 17 + /** Are unapplied type constructors allowed here? Formerly HKmode. */ + final val TypeConstructorAllowed: ContextMode = 1 << 16 /** TODO: The "sticky modes" are EXPRmode, PATTERNmode, TYPEmode. * To mimick the sticky mode behavior, when captain stickyfingers @@ -1391,27 +1390,26 @@ object ContextMode { * ones listed here. */ final val FormerNonStickyModes: ContextMode = ( - PatternAlternative | StarPatterns | SuperInit | SecondTry | ReturnExpr | TypeConstructor | TypeApplication + PatternAlternative | StarPatterns | SuperInit | SecondTry | ReturnExpr | TypeConstructorAllowed ) final val DefaultMode: ContextMode = MacrosEnabled private val contextModeNameMap = Map( - ReportErrors -> "ReportErrors", - BufferErrors -> "BufferErrors", - AmbiguousErrors -> "AmbiguousErrors", - ConstructorSuffix -> "ConstructorSuffix", - SelfSuperCall -> "SelfSuperCall", - ImplicitsEnabled -> "ImplicitsEnabled", - MacrosEnabled -> "MacrosEnabled", - Checking -> "Checking", - ReTyping -> "ReTyping", - PatternAlternative -> "PatternAlternative", - StarPatterns -> "StarPatterns", - SuperInit -> "SuperInit", - SecondTry -> "SecondTry", - TypeConstructor -> "TypeConstructor", - TypeApplication -> "TypeApplication" + ReportErrors -> "ReportErrors", + BufferErrors -> "BufferErrors", + AmbiguousErrors -> "AmbiguousErrors", + ConstructorSuffix -> "ConstructorSuffix", + SelfSuperCall -> "SelfSuperCall", + ImplicitsEnabled -> "ImplicitsEnabled", + MacrosEnabled -> "MacrosEnabled", + Checking -> "Checking", + ReTyping -> "ReTyping", + PatternAlternative -> "PatternAlternative", + StarPatterns -> "StarPatterns", + SuperInit -> "SuperInit", + SecondTry -> "SecondTry", + TypeConstructorAllowed -> "TypeConstructorAllowed" ) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala index 5d627e13a5..aa05c97c08 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala @@ -331,7 +331,7 @@ abstract class Duplicators extends Analyzer { super.typed(atPos(tree.pos)(tree1)) */ case Match(scrut, cases) => - val scrut1 = typedExprByValue(scrut) + val scrut1 = typedByValueExpr(scrut) val scrutTpe = scrut1.tpe.widen val cases1 = { if (scrutTpe.isFinalType) cases filter { diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 5b1f7160b7..cf53f57e24 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -605,7 +605,7 @@ trait Typers extends Adaptations with Tags { inferExprAlternative(tree, pt) val sym = tree.symbol - val isStableIdPattern = mode.typingPatternNotFun && tree.isTerm + val isStableIdPattern = mode.typingPatternNotConstructor && tree.isTerm def isModuleTypedExpr = ( sym.isStable @@ -893,13 +893,13 @@ trait Typers extends Adaptations with Tags { } def adaptType(): Tree = { - // @M When not typing a higher-kinded type (!context.inTypeConstructor) + // @M When not typing a type constructor (!context.inTypeConstructorAllowed) // or raw type (tree.symbol.isJavaDefined && context.unit.isJava), types must be of kind *, // and thus parameterized types must be applied to their type arguments // @M TODO: why do kind-* tree's have symbols, while higher-kinded ones don't? - def kindStarRequired = ( + def properTypeRequired = ( tree.hasSymbolField - && !context.inTypeConstructor + && !context.inTypeConstructorAllowed && !(tree.symbol.isJavaDefined && context.unit.isJava) ) // @M: don't check tree.tpe.symbol.typeParams. check tree.tpe.typeParams!!! @@ -907,7 +907,7 @@ trait Typers extends Adaptations with Tags { // @M: removed check for tree.hasSymbolField and replace tree.symbol by tree.tpe.symbol // (TypeTree's must also be checked here, and they don't directly have a symbol) def kindArityMismatch = ( - context.inTypeConstructor + context.inTypeConstructorAllowed && !sameLength(tree.tpe.typeParams, pt.typeParams) ) // Note that we treat Any and Nothing as kind-polymorphic. @@ -925,7 +925,7 @@ trait Typers extends Adaptations with Tags { // but this needs additional investigation, because it crashes t5228, gadts1 and maybe something else if (mode.inFunMode) tree - else if (kindStarRequired && tree.symbol.typeParams.nonEmpty) // (7) + else if (properTypeRequired && tree.symbol.typeParams.nonEmpty) // (7) MissingTypeParametersError(tree) else if (kindArityMismatch && !kindArityMismatchOk) // (7.1) @M: check kind-arity KindArityMismatchError(tree, pt) @@ -1051,7 +1051,7 @@ trait Typers extends Adaptations with Tags { } def insertApply(): Tree = { - assert(!context.inTypeConstructor, mode) //@M + assert(!context.inTypeConstructorAllowed, mode) //@M val adapted = adaptToName(tree, nme.apply) def stabilize0(pre: Type): Tree = stabilize(adapted, pre, MonoQualifierModes, WildcardType) @@ -1235,12 +1235,12 @@ trait Typers extends Adaptations with Tags { adaptType() else if (mode.typingExprNotFun && treeInfo.isMacroApplication(tree)) macroExpandApply(this, tree, mode, pt) - else if (mode.typingPatternFun) + else if (mode.typingConstructorPattern) adaptConstrPattern() else if (shouldInsertApply(tree)) insertApply() else if (hasUndetsInMonoMode) { // (9) - assert(!context.inTypeConstructor, context) //@M + assert(!context.inTypeConstructorAllowed, context) //@M instantiatePossiblyExpectingUnit(tree, mode, pt) } else if (tree.tpe <:< pt) @@ -1264,7 +1264,7 @@ trait Typers extends Adaptations with Tags { adapt(tree setType arg, mode, pt, original) case tp if mode.typingExprNotLhs && isExistentialType(tp) => adapt(tree setType tp.dealias.skolemizeExistential(context.owner, tree), mode, pt, original) - case PolyType(tparams, restpe) if mode.inNone(TAPPmode | PATTERNmode) && !context.inTypeConstructor => // (3) + case PolyType(tparams, restpe) if mode.inNone(TAPPmode | PATTERNmode) && !context.inTypeConstructorAllowed => // (3) // assert((mode & HKmode) == 0) //@M a PolyType in HKmode represents an anonymous type function, // we're in HKmode since a higher-kinded type is expected --> hence, don't implicitly apply it to type params! // ticket #2197 triggered turning the assert into a guard @@ -2544,7 +2544,7 @@ trait Typers extends Adaptations with Tags { // takes untyped sub-trees of a match and type checks them def typedMatch(selector: Tree, cases: List[CaseDef], mode: Mode, pt: Type, tree: Tree = EmptyTree): Match = { - val selector1 = checkDead(typedExprByValue(selector)) + val selector1 = checkDead(typedByValueExpr(selector)) val selectorTp = packCaptured(selector1.tpe.widen).skolemizeExistential(context.owner, selector) val casesTyped = typedCases(cases, selectorTp, pt) @@ -2925,7 +2925,7 @@ trait Typers extends Adaptations with Tags { } else newTyper(context.make(stat, exprOwner)) // XXX this creates a spurious dead code warning if an exception is thrown // in a constructor, even if it is the only thing in the constructor. - val result = checkDead(localTyper.typedExprByValue(stat)) + val result = checkDead(localTyper.typedByValueExpr(stat)) if (treeInfo.isSelfOrSuperConstrCall(result)) { context.inConstructorSuffix = true @@ -4232,11 +4232,11 @@ trait Typers extends Adaptations with Tags { // // setter-rewrite has been done above, so rule out methods here, but, wait a minute, why are we assigning to non-variables after erasure?! // (phase.erasedTypes && varsym.isValue && !varsym.isMethod)) { if (varsym.isVariable || varsym.isValue && phase.erasedTypes) { - val rhs1 = typedExprByValue(rhs, lhs1.tpe) + val rhs1 = typedByValueExpr(rhs, lhs1.tpe) treeCopy.Assign(tree, lhs1, checkDead(rhs1)) setType UnitClass.tpe } else if(dyna.isDynamicallyUpdatable(lhs1)) { - val rhs1 = typedExprByValue(rhs) + val rhs1 = typedByValueExpr(rhs) val t = Apply(lhs1, List(rhs1)) dyna.wrapErrors(t, _.typed1(t, mode, pt)) } @@ -4244,7 +4244,7 @@ trait Typers extends Adaptations with Tags { } def typedIf(tree: If): If = { - val cond1 = checkDead(typedExprByValue(tree.cond, BooleanClass.tpe)) + val cond1 = checkDead(typedByValueExpr(tree.cond, BooleanClass.tpe)) // One-legged ifs don't need a lot of analysis if (tree.elsep.isEmpty) return treeCopy.If(tree, cond1, typed(tree.thenp, UnitClass.tpe), tree.elsep) setType UnitClass.tpe @@ -4318,7 +4318,7 @@ trait Typers extends Adaptations with Tags { ReturnWithoutTypeError(tree, enclMethod.owner) } else { - val expr1 = context withinReturnExpr typedExprByValue(expr, restpt.tpe) + val expr1 = context withinReturnExpr typedByValueExpr(expr, restpt.tpe) // Warn about returning a value if no value can be returned. if (restpt.tpe.typeSymbol == UnitClass) { // The typing in expr1 says expr is Unit (it has already been coerced if @@ -4817,13 +4817,13 @@ trait Typers extends Adaptations with Tags { /* A symbol qualifies if: * - it exists * - it is not stale (stale symbols are made to disappear here) - * - if we are in a pattern constructor, method definitions do not qualify + * - if we are in a constructor pattern, method definitions do not qualify * unless they are stable. Otherwise, 'case x :: xs' would find the :: method. */ def qualifies(sym: Symbol) = ( sym.hasRawInfo && reallyExists(sym) - && !(mode.typingPatternFun && sym.isMethod && !sym.isStable) + && !(mode.typingConstructorPattern && sym.isMethod && !sym.isStable) ) /* Attribute an identifier consisting of a simple name or an outer reference. @@ -4882,7 +4882,7 @@ trait Typers extends Adaptations with Tags { def typedIdentOrWildcard(tree: Ident) = { val name = tree.name if (Statistics.canEnable) Statistics.incCounter(typedIdentCount) - if ((name == nme.WILDCARD && mode.typingPatternNotFun) || + if ((name == nme.WILDCARD && mode.typingPatternNotConstructor) || (name == tpnme.WILDCARD && mode.inTypeMode)) tree setType makeFullyDefined(pt) else @@ -5048,7 +5048,7 @@ trait Typers extends Adaptations with Tags { } def typedThrow(tree: Throw) = { - val expr1 = typedExprByValue(tree.expr, ThrowableClass.tpe) + val expr1 = typedByValueExpr(tree.expr, ThrowableClass.tpe) treeCopy.Throw(tree, expr1) setType NothingClass.tpe } @@ -5392,7 +5392,7 @@ trait Typers extends Adaptations with Tags { ret } - def typedExprByValue(tree: Tree, pt: Type = WildcardType): Tree = typed(tree, EXPRmode | BYVALmode, pt) + def typedByValueExpr(tree: Tree, pt: Type = WildcardType): Tree = typed(tree, EXPRmode | BYVALmode, pt) def typedPos(pos: Position, mode: Mode, pt: Type)(tree: Tree) = typed(atPos(pos)(tree), mode, pt) def typedPos(pos: Position)(tree: Tree) = typed(atPos(pos)(tree)) @@ -5465,10 +5465,10 @@ trait Typers extends Adaptations with Tags { /** Types a higher-kinded type tree -- pt denotes the expected kind*/ def typedHigherKindedType(tree: Tree, mode: Mode, pt: Type): Tree = if (pt.typeParams.isEmpty) typedType(tree, mode) // kind is known and it's * - else context withinTypeConstructor typed(tree, NOmode, pt) + else context withinTypeConstructorAllowed typed(tree, NOmode, pt) def typedHigherKindedType(tree: Tree, mode: Mode): Tree = - context withinTypeConstructor typed(tree) + context withinTypeConstructorAllowed typed(tree) /** Types a type constructor tree used in a new or supertype */ def typedTypeConstructor(tree: Tree, mode: Mode): Tree = { diff --git a/src/reflect/scala/reflect/internal/Mode.scala b/src/reflect/scala/reflect/internal/Mode.scala index 7a7c6c8c76..027e3a340a 100644 --- a/src/reflect/scala/reflect/internal/Mode.scala +++ b/src/reflect/scala/reflect/internal/Mode.scala @@ -124,17 +124,17 @@ final class Mode private (val bits: Int) extends AnyVal { def inTappMode = inAll(TAPPmode) def inTypeMode = inAll(TYPEmode) - def typingExprByValue = inAll(EXPRmode | BYVALmode) - def typingExprFun = inAll(EXPRmode | FUNmode) - def typingExprNotFun = in(all = EXPRmode, none = FUNmode) - def typingExprNotFunNotLhs = in(all = EXPRmode, none = FUNmode | LHSmode) - def typingExprNotLhs = in(all = EXPRmode, none = LHSmode) - def typingExprNotValue = in(all = EXPRmode, none = BYVALmode) - def typingMonoExprByValue = in(all = EXPRmode | BYVALmode, none = POLYmode) - def typingPatternFun = inAll(PATTERNmode | FUNmode) - def typingPatternNotFun = in(all = PATTERNmode, none = FUNmode) - def typingPatternOrTypePat = inAny(PATTERNmode | TYPEPATmode) - def typingTypeByValue = inAll(TYPEmode | BYVALmode) + def typingExprByValue = inAll(EXPRmode | BYVALmode) + def typingExprFun = inAll(EXPRmode | FUNmode) + def typingExprNotFun = in(all = EXPRmode, none = FUNmode) + def typingExprNotFunNotLhs = in(all = EXPRmode, none = FUNmode | LHSmode) + def typingExprNotLhs = in(all = EXPRmode, none = LHSmode) + def typingExprNotValue = in(all = EXPRmode, none = BYVALmode) + def typingMonoExprByValue = in(all = EXPRmode | BYVALmode, none = POLYmode) + def typingConstructorPattern = inAll(PATTERNmode | FUNmode) + def typingPatternNotConstructor = in(all = PATTERNmode, none = FUNmode) + def typingPatternOrTypePat = inAny(PATTERNmode | TYPEPATmode) + def typingTypeByValue = inAll(TYPEmode | BYVALmode) override def toString = if (this == NOmode) "NOmode" -- cgit v1.2.3