diff options
Diffstat (limited to 'src/compiler/scala')
3 files changed, 34 insertions, 3 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/AnnotationCheckers.scala b/src/compiler/scala/tools/nsc/symtab/AnnotationCheckers.scala index d26c5d65a0..be2e520554 100644 --- a/src/compiler/scala/tools/nsc/symtab/AnnotationCheckers.scala +++ b/src/compiler/scala/tools/nsc/symtab/AnnotationCheckers.scala @@ -47,6 +47,13 @@ trait AnnotationCheckers { * before. If the implementing class cannot do the adaptiong, it * should return the tree unchanged.*/ def adaptAnnotations(tree: Tree, mode: Int, pt: Type): Tree = tree + + /** Adapt the type of a return expression. The decision of an annotation checker + * whether the type should be adapted is based on the type of the expression + * which is returned, as well as the result type of the method (pt). + * By default, this method simply returns the passed `default` type. + */ + def adaptTypeOfReturn(tree: Tree, pt: Type, default: => Type): Type = default } /** The list of annotation checkers that have been registered */ @@ -117,4 +124,23 @@ trait AnnotationCheckers { annotationCheckers.foldLeft(tree)((tree, checker) => checker.adaptAnnotations(tree, mode, pt)) } + + /** Let a registered annotation checker adapt the type of a return expression. + * Annotation checkers that cannot do the adaptation should simply return + * the `default` argument. + * + * Note that the result is undefined if more than one annotation checker + * returns an adapted type which is not a subtype of `default`. + */ + def adaptTypeOfReturn(tree: Tree, pt: Type, default: => Type): Type = { + val adaptedTypes = annotationCheckers flatMap { checker => + val adapted = checker.adaptTypeOfReturn(tree, pt, default) + if (!(adapted <:< default)) List(adapted) + else List() + } + adaptedTypes match { + case fst :: _ => fst + case List() => default + } + } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Modes.scala b/src/compiler/scala/tools/nsc/typechecker/Modes.scala index ad4be4662c..b8308ebabf 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Modes.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Modes.scala @@ -86,6 +86,10 @@ trait Modes { */ final val TYPEPATmode = 0x10000 + /** RETmode is set when we are typing a return expression. + */ + final val RETmode = 0x20000 + final private val StickyModes = EXPRmode | PATTERNmode | TYPEmode | ALTmode final def onlyStickyModes(mode: Int) = @@ -130,4 +134,4 @@ trait Modes { def modeString(mode: Int): String = if (mode == 0) "NOmode" else (modeNameMap filterKeys (bit => inAllModes(mode, bit))).values mkString " " -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 1a77ee6a9b..05b36d128e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3181,7 +3181,7 @@ trait Typers extends Modes { errorTree(tree, enclMethod.owner + " has return statement; needs result type") else { context.enclMethod.returnsSeen = true - val expr1: Tree = typed(expr, EXPRmode | BYVALmode, restpt.tpe) + val expr1: Tree = typed(expr, EXPRmode | BYVALmode | RETmode, 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 @@ -3190,7 +3190,8 @@ trait Typers extends Modes { if (typed(expr).tpe.typeSymbol != UnitClass) unit.warning(tree.pos, "enclosing method " + name + " has result type Unit: return value discarded") } - treeCopy.Return(tree, checkDead(expr1)) setSymbol enclMethod.owner setType NothingClass.tpe + treeCopy.Return(tree, checkDead(expr1)).setSymbol(enclMethod.owner) + .setType(adaptTypeOfReturn(expr1, restpt.tpe, NothingClass.tpe)) } } } |