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