diff options
17 files changed, 594 insertions, 484 deletions
diff --git a/src/compiler/scala/reflect/macros/runtime/Typers.scala b/src/compiler/scala/reflect/macros/runtime/Typers.scala index 4592f640bd..f60b8dfeb4 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/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 82e6de87e3..9794497667 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 @@ -235,6 +241,12 @@ 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 + 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 @@ -344,11 +356,27 @@ 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) + @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) + @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. + */ + @inline final def withinReturnExpr[T](op: => T): T = { + enclMethod.returnsSeen = true + withMode(enabled = ReturnExpr)(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 = { @@ -1325,22 +1353,65 @@ 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. */ + 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.<init>. 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 + + /** 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 + + /** 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( - 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", + SuperInit -> "SuperInit", + SecondTry -> "SecondTry", + TypeConstructor -> "TypeConstructor", + TypeApplication -> "TypeApplication" ) } 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/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index ecae55562b..2cd2f9380b 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) => typer.instantiate(delayed, EXPRmode, WildcardType) case Skipped(skipped) => 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/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 2de59056ef..5b1f7160b7 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. @@ -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. @@ -588,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.inPatternNotFunMode && 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 & (EXPRmode | QUALmode)) == EXPRmode && !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 { @@ -638,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 */ @@ -803,9 +823,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, @@ -828,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) @@ -847,59 +869,67 @@ 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) - instantiate(typed(tree0, mode, WildcardType), mode, pt) - } else + // #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), mode, pt) + 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 = { - 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 + // @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) + 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 (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? + else if (kindStarRequired && tree.symbol.typeParams.nonEmpty) // (7) 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) - 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). + 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 } @@ -1021,9 +1051,10 @@ 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) + def stabilize0(pre: Type): Tree = stabilize(adapted, pre, MonoQualifierModes, WildcardType) + // TODO reconcile the overlap between Typers#stablize and TreeGen.stabilize val qual = adapted match { case This(_) => @@ -1044,31 +1075,196 @@ 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 <local Test>)]] where type ?0(in value <local Test>) <: 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) + 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 && hasPolymorphicApply + else + hasMonomorphicApply + ) + } + def shouldInsertApply(tree: Tree) = mode.typingExprFun && { + tree.tpe match { + case _: MethodType | _: OverloadedType | _: PolyType => false + case _ => applyPossible + } + } + if (tree.isType) + adaptType() + else if (mode.typingExprNotFun && treeInfo.isMacroApplication(tree)) + macroExpandApply(this, tree, mode, pt) + else if (mode.typingPatternFun) + adaptConstrPattern() + else if (shouldInsertApply(tree)) + insertApply() + else if (hasUndetsInMonoMode) { // (9) + assert(!context.inTypeConstructor, context) //@M + instantiatePossiblyExpectingUnit(tree, mode, pt) + } + else if (tree.tpe <:< pt) + tree + else + fallbackAfterVanillaAdapt() + } // 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 PolyType(tparams, restpe) if mode.inNone(TAPPmode | PATTERNmode | HKmode) => // (3) + 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) // 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 @@ -1077,168 +1273,20 @@ 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 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.inExprModeButNot(FUNmode) && treeInfo.isMacroApplication(tree)) - macroExpandApply(this, tree, mode, pt) - else if (mode.inAll(PATTERNmode | FUNmode)) - adaptConstrPattern() - else if (shouldInsertApply(tree)) - insertApply() - else if (context.undetparams.nonEmpty && !mode.inPolyMode) { // (9) - assert(!mode.inHKMode, mode) //@M - instantiatePossiblyExpectingUnit(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 <local Test>)]] where type ?0(in value <local Test>) <: 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 - } + vanillaAdapt(tree) } } @@ -1260,7 +1308,7 @@ trait Typers extends Adaptations with Tags { } def instantiatePossiblyExpectingUnit(tree: Tree, mode: Mode, pt: Type): Tree = { - if (mode.inExprModeButNot(FUNmode) && pt.typeSymbol == UnitClass) + if (mode.typingExprNotFun && pt.typeSymbol == UnitClass) instantiateExpectingUnit(tree, mode) else instantiate(tree, mode, pt) @@ -2496,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(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) @@ -2520,7 +2568,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) @@ -2877,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.typed(stat, EXPRmode | BYVALmode, WildcardType)) + val result = checkDead(localTyper.typedExprByValue(stat)) if (treeInfo.isSelfOrSuperConstrCall(result)) { context.inConstructorSuffix = true @@ -2991,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 t = withCondConstrTyper((mode & SCCmode) != NOmode)(_.typed(arg, typedMode, pt)) + val t = withCondConstrTyper(mode.inSccMode)(_.typed(arg, typedMode, pt)) checkDead.inMode(typedMode, t) } @@ -3007,19 +3055,18 @@ 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 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) mode.onlySticky else mode.onlySticky | BYVALmode + def body = typedArg(args.head, mode, typedMode, adapted.head) + def arg1 = if (isVarArgs) context.withinStarPatterns(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) @@ -3164,7 +3211,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) ) @@ -3508,7 +3555,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 { @@ -3547,7 +3594,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 :: _) => @@ -3578,7 +3625,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 @@ -4006,13 +4053,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) @@ -4129,7 +4172,9 @@ trait Typers extends Adaptations with Tags { else context.owner.newValue(name, tree.pos) if (name != nme.WILDCARD) { - if (mode.inAll(ALTmode)) VariableInPatternAlternativeError(tree) + if (context.inPatAlternative) + VariableInPatternAlternativeError(tree) + namer.enterInScope(sym) } @@ -4162,7 +4207,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 @@ -4187,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 = 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)) } @@ -4199,7 +4244,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 @@ -4271,9 +4316,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 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 @@ -4429,7 +4474,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 withinSecondTry typed1(tree1, mode, pt) } case _ => () } @@ -4443,14 +4488,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) @@ -4475,15 +4520,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 inExprModeButNot SNDTRYmode - case _ => false - } + || isImplicitMethodType(fun2.tpe) ) + val isFirstTry = fun2 match { + case Select(_, _) => !noSecondTry && mode.inExprMode + case _ => false + } if (isFirstTry) tryTypedApply(fun2, args) else @@ -4601,7 +4645,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) @@ -4645,7 +4689,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) @@ -4733,44 +4777,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: @@ -4782,7 +4823,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. @@ -4805,7 +4846,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) @@ -4841,8 +4882,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) @@ -4942,14 +4983,15 @@ trait Typers extends Adaptations with Tags { newTyper(context.makeNewScope(ddef, sym)).constrTyperIf(isConstrDefaultGetter) } - def typedAlternative(alt: Alternative) = { - val alts1 = alt.trees mapConserve (alt => typed(alt, mode | ALTmode, pt)) - treeCopy.Alternative(tree, alts1) setType pt - } - + def typedAlternative(alt: Alternative) = ( + context withinPatAlternative ( + treeCopy.Alternative(tree, alt.trees mapConserve (alt => typed(alt, mode, pt))) setType pt + ) + ) 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) } @@ -5006,7 +5048,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 } @@ -5029,7 +5071,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 { @@ -5039,7 +5081,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)) => @@ -5053,7 +5095,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) @@ -5081,7 +5123,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 ? @@ -5163,7 +5205,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 @@ -5346,10 +5388,12 @@ 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 } + 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 @@ -5359,13 +5403,16 @@ 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) /** Types qualifier `tree` of a select node. * 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`. @@ -5376,8 +5423,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 withinSuperInit typed(qual, PolyQualifierModes) /** Types a pattern with prototype `pt` */ def typedPattern(tree: Tree, pt: Type): Tree = { @@ -5401,7 +5451,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 } } @@ -5415,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 typed(tree, HKmode, pt) + else context withinTypeConstructor typed(tree, NOmode, pt) def typedHigherKindedType(tree: Tree, mode: Mode): Tree = - typed(tree, HKmode, WildcardType) + context withinTypeConstructor typed(tree) /** Types a type constructor tree used in a new or supertype */ def typedTypeConstructor(tree: Tree, mode: Mode): Tree = { @@ -5474,17 +5524,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/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index f81ec610ef..59408096a3 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/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala index beab271a3b..e6153596f7 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala @@ -138,7 +138,7 @@ abstract class CPSAnnotationChecker extends CPSUtils { /* // not precise enough -- still relying on addAnnotations to remove things from ValDef symbols - if ((mode & TYPEmode) != 0 && (mode & BYVALmode) != 0) { + if (mode.inAllModes(TYPEmode | BYVALmode)) { if (!annots1.isEmpty) { return true } @@ -147,7 +147,7 @@ abstract class CPSAnnotationChecker extends CPSUtils { /* this interferes with overloading resolution - if ((mode & BYVALmode) != 0 && tree.tpe <:< pt) { + if (mode.inByValMode && tree.tpe <:< pt) { vprintln("already compatible, can't adapt further") return false } @@ -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) { @@ -193,19 +193,15 @@ abstract class CPSAnnotationChecker extends CPSUtils { vprintln("adapt annotations " + tree + " / " + tree.tpe + " / " + mode + " / " + pt) - val patMode = mode.inPatternMode - val exprMode = mode.inExprMode - val byValMode = mode.inByValMode - val retMode = mode.inRetMode - - val annotsTree = cpsParamAnnotation(tree.tpe) - val annotsExpected = cpsParamAnnotation(pt) + val annotsTree = cpsParamAnnotation(tree.tpe) + val annotsExpected = cpsParamAnnotation(pt) + def isMissingExpectedAnnots = annotsTree.isEmpty && annotsExpected.nonEmpty // not sure I rephrased this comment correctly: - // replacing `patMode` in the condition below by `patMode || ((mode & TYPEmode) != 0 && (mode & BYVALmode))` + // replacing `mode.inPatternMode` in the condition below by `mode.inPatternMode || mode.inAllModes(TYPEmode | BYVALmode)` // doesn't work correctly -- still relying on addAnnotations to remove things from ValDef symbols - if (patMode && !annotsTree.isEmpty) tree modifyType removeAllCPSAnnotations - else if (exprMode && !byValMode && !hasPlusMarker(tree.tpe) && annotsTree.isEmpty && annotsExpected.nonEmpty) { // shiftUnit + if (mode.inPatternMode && annotsTree.nonEmpty) tree modifyType removeAllCPSAnnotations + else if (mode.typingExprNotValue && !hasPlusMarker(tree.tpe) && isMissingExpectedAnnots) { // shiftUnit // add a marker annotation that will make tree.tpe behave as pt, subtyping wise // tree will look like having any possible annotation //println("adapt annotations " + tree + " / " + tree.tpe + " / " + Integer.toHexString(mode) + " / " + pt) @@ -217,13 +213,13 @@ abstract class CPSAnnotationChecker extends CPSUtils { val res = tree modifyType (_ withAnnotations newPlusMarker() :: annotsExpected) // needed for #1807 vprintln("adapted annotations (not by val) of " + tree + " to " + res.tpe) res - } else if (exprMode && byValMode && !hasMinusMarker(tree.tpe) && annotsTree.nonEmpty) { // dropping annotation + } else if (mode.typingExprByValue && !hasMinusMarker(tree.tpe) && annotsTree.nonEmpty) { // dropping annotation // add a marker annotation that will make tree.tpe behave as pt, subtyping wise // tree will look like having no annotation val res = tree modifyType addMinusMarker vprintln("adapted annotations (by val) of " + tree + " to " + res.tpe) res - } else if (retMode && !hasPlusMarker(tree.tpe) && annotsTree.isEmpty && annotsExpected.nonEmpty) { + } 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 @@ -231,7 +227,7 @@ abstract class CPSAnnotationChecker extends CPSUtils { // (annotsExpected.nonEmpty == cpsParamAnnotation(pt).nonEmpty) // note 2: we are not adding the expected cps annotations, since they will be added // by adaptTypeOfReturn (see below). - val res = tree modifyType (_ withAnnotations List(newPlusMarker())) + val res = tree modifyType (_ withAnnotation newPlusMarker()) vprintln("adapted annotations (return) of " + tree + " to " + res.tpe) res } else tree diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala index 90534a9865..73ca74f08e 100644 --- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala +++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala @@ -40,8 +40,7 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => // monomorphic one by introducing existentials, see SI-7009 for details existentialAbstraction(throwableSym.typeParams, throwableSym.tpe) } - val throwsAnn = AnnotationInfo(appliedType(definitions.ThrowsClass, throwableTpe), List(Literal(Constant(throwableTpe))), Nil) - withAnnotations(List(throwsAnn)) + this withAnnotation AnnotationInfo(appliedType(ThrowsClass, throwableTpe), List(Literal(Constant(throwableTpe))), Nil) } /** Tests for, get, or remove an annotation */ diff --git a/src/reflect/scala/reflect/internal/Mode.scala b/src/reflect/scala/reflect/internal/Mode.scala index 516e96cbb3..7a7c6c8c76 100644 --- a/src/reflect/scala/reflect/internal/Mode.scala +++ b/src/reflect/scala/reflect/internal/Mode.scala @@ -48,35 +48,10 @@ object Mode { */ final val TAPPmode: Mode = 0x080 - /** SUPERCONSTRmode is set for the super - * in a superclass constructor call super.<init>. - */ - 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. - */ - final val SNDTRYmode: Mode = 0x200 - /** LHSmode is set for the left-hand side of an assignment. */ 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. - */ - 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,11 +65,11 @@ 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 | ALTmode + 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. */ @@ -107,13 +82,13 @@ object Mode { (1 << 5) -> "POLYmode", (1 << 6) -> "QUALmode", (1 << 7) -> "TAPPmode", - (1 << 8) -> "SUPERCONSTRmode", - (1 << 9) -> "SNDTRYmode", + (1 << 8) -> "<>", // formerly SUPERCONSTRmode + (1 << 9) -> "<>", // formerly SNDTRYmode (1 << 10) -> "LHSmode", - (1 << 11) -> "<DOES NOT EXIST mode>", - (1 << 12) -> "STARmode", - (1 << 13) -> "ALTmode", - (1 << 14) -> "HKmode", + (1 << 11) -> "<>", + (1 << 12) -> "<>", // formerly STARmode + (1 << 13) -> "<>", // formerly ALTmode + (1 << 14) -> "<>", // formerly HKmode (1 << 15) -> "BYVALmode", (1 << 16) -> "TYPEPATmode" ).map({ case (k, v) => Mode(k) -> v }) @@ -121,32 +96,47 @@ 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 onlySticky = this & Mode.StickyModes - def forFunMode = this & (Mode.StickyModes | SCCmode) | FUNmode | POLYmode | BYVALmode - def forTypeMode = - 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 inHKMode = inAll(HKmode) - def inFunMode = inAll(FUNmode) - def inPolyMode = inAll(POLYmode) - def inPatternMode = inAll(PATTERNmode) - def inExprMode = inAll(EXPRmode) - def inByValMode = inAll(BYVALmode) - def inRetMode = inAll(RETmode) - - def inPatternNotFunMode = inPatternMode && !inFunMode - def inExprModeOr(others: Mode) = inAny(EXPRmode | others) - def inExprModeButNot(prohibited: Mode) = inAll(EXPRmode) && inNone(prohibited) + def onlyTypePat = this & TYPEPATmode + 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 + def inNone(prohibited: Mode) = (this & prohibited) == NOmode + + /** 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 inPatternMode = inAll(PATTERNmode) + def inPolyMode = inAll(POLYmode) + def inQualMode = inAll(QUALmode) + def inSccMode = inAll(SCCmode) + 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) 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 a8fc55e677..eb40733327 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -3959,6 +3959,16 @@ trait Types case _ => false } + def isExistentialType(tp: Type): Boolean = tp.dealias match { + case ExistentialType(_, _) => true + 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 diff --git a/src/scaladoc/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala b/src/scaladoc/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala index 6cefe34887..8d29bce27e 100644 --- a/src/scaladoc/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala +++ b/src/scaladoc/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala @@ -170,7 +170,7 @@ trait ModelFactoryImplicitSupport { val newContext = context.makeImplicit(context.ambiguousErrors) newContext.macrosEnabled = false val newTyper = global.analyzer.newTyper(newContext) - newTyper.silent(_.typed(appliedTree, EXPRmode, WildcardType), reportAmbiguousErrors = false) match { + newTyper.silent(_.typed(appliedTree), reportAmbiguousErrors = false) match { case global.analyzer.SilentResultValue(t: Tree) => t case global.analyzer.SilentTypeError(err) => diff --git a/test/files/run/analyzerPlugins.check b/test/files/run/analyzerPlugins.check index 641fbfff6b..e3ab554d4c 100644 --- a/test/files/run/analyzerPlugins.check +++ b/test/files/run/analyzerPlugins.check @@ -7,7 +7,7 @@ annotationsConform(Int @testAnn, Int) [2] annotationsConform(Int(1) @testAnn, Int) [1] annotationsConform(Int(1), Int @testAnn) [1] annotationsConform(Nothing, Int @testAnn) [2] -annotationsConform(String @testAnn, String) [1] +annotationsConform(String @testAnn, String) [2] canAdaptAnnotations(Trees$Ident, String) [1] canAdaptAnnotations(Trees$Select, ?) [1] canAdaptAnnotations(Trees$Select, Boolean @testAnn) [1] |