@@ -3089,13 +3089,32 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
30893089 // todo: make sure dependent method types do not depend on implicits or by-name params
30903090 }
30913091
3092- /** (1) Check that the signature of the class member does not return a repeated parameter type
3093- * (2) Make sure the definition's symbol is `sym`.
3094- * (3) Set the `defTree` of `sym` to be `mdef`.
3092+ /** (1) Check that the signature of the class member does not return a repeated parameter type.
3093+ * (2) Check that the signature of the public class member does not expose a flexible type.
3094+ * (3) Make sure the definition's symbol is `sym`.
3095+ * (4) Set the `defTree` of `sym` to be `mdef`.
30953096 */
30963097 private def postProcessInfo (mdef : MemberDef , sym : Symbol )(using Context ): MemberDef =
30973098 if (! sym.isOneOf(Synthetic | InlineProxy | Param ) && sym.info.finalResultType.isRepeatedParam)
30983099 report.error(em " Cannot return repeated parameter type ${sym.info.finalResultType}" , sym.srcPos)
3100+
3101+ // Warn if a public method/field exposes FlexibleType in its result type under explicit nulls
3102+ // and encourage explicit annotation.
3103+ if ctx.phase.isTyper && ctx.explicitNulls && ! ctx.isJava
3104+ && sym.exists && sym.isPublic && sym.owner.isClass
3105+ && ! sym.isOneOf(Synthetic | InlineProxy | Param ) then
3106+ val resTp = sym.info.finalResultType
3107+ if resTp.existsPart(_.isInstanceOf [FlexibleType ], StopAt .Static ) then
3108+ val suggestion = resTp match
3109+ case ft : FlexibleType =>
3110+ val hi = ft.hi
3111+ i " Consider annotating the type as ${hi} or ${hi} | Null explicitly "
3112+ case _ => " Consider annotating the type explicitly"
3113+ report.warning(
3114+ em " Public ${if sym.is(Method ) then " method" else " field" } ${sym.show} exposes a flexible type ${resTp} in its inferred signature. $suggestion" ,
3115+ sym.srcPos
3116+ )
3117+
30993118 mdef.ensureHasSym(sym)
31003119 mdef.setDefTree
31013120
0 commit comments