-
Notifications
You must be signed in to change notification settings - Fork 1.1k
warn about unnecessary uses of .nn #23327
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
213491f
7951635
cf9883f
d705c1b
31afb35
56ac3a6
b96d7e3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1088,7 +1088,19 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer | |
errorTree(tree, em"cannot convert to type selection") // will never be printed due to fallback | ||
} | ||
|
||
if (tree.qualifier.isType) { | ||
def warnUnnecessaryNN(tree: Tree): Unit = { | ||
if ctx.explicitNulls then { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you agree we should check unnecessary nn even without explicit nulls? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could, but I didn't want to rock the boat too much before we fine-tune which corner cases should/shouldn't warn. |
||
val symbol = tree.symbol | ||
if symbol.exists && symbol.owner == defn.ScalaPredefModuleClass && symbol.name == nme.nn then | ||
tree match | ||
case Apply(_, args) => | ||
if(args.head.tpe.isNotNull) then report.warning("Unnecessary .nn: qualifier is already not null", tree) | ||
if pt.admitsNull then report.warning("Unnecessary .nn: expected type admits null", tree) | ||
case _ => | ||
} | ||
} | ||
|
||
val tree1 = if (tree.qualifier.isType) { | ||
val qual1 = typedType(tree.qualifier, shallowSelectionProto(tree.name, pt, this, tree.nameSpan)) | ||
assignType(cpy.Select(tree)(qual1, tree.name), qual1) | ||
} | ||
|
@@ -1098,6 +1110,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer | |
tryAlternatively(typeSelectOnTerm)(tryJavaSelectOnType) | ||
else | ||
typeSelectOnTerm | ||
|
||
warnUnnecessaryNN(tree1) | ||
tree1 | ||
} | ||
|
||
def typedThis(tree: untpd.This)(using Context): Tree = { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
def f1(s: String): String = s.nn // warn | ||
def f2(s: String|Null): String|Null = s.nn // warn | ||
def f3(s: String|Null): Any = s.nn // warn | ||
def f4(s: String|Null): String = s.nn | ||
|
||
def f5[T >: String](s: String|Null): T = s.nn | ||
def f6[T >: String|Null](s: String|Null): T = s.nn // warn | ||
|
||
def f5a[T <: String](s: T): String = s.nn // warn | ||
|
||
// flexible types | ||
def f7(s: String|Null) = "".concat(s.nn) // warn | ||
def f8(s: String): String = s.trim().nn // OK because the .nn could be useful as a dynamic null check | ||
|
||
|
||
def f9(s: String|Null): String = | ||
if(s == null) "default" | ||
else s.nn // warn |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we are basically checking if a type has
Null
as a subtype, I'm not sure whether we should widen a singleton type.For example,
I'd like to allow
ss.nn
to say if it returns a value, the value is equal tos
and not null.