-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Apply flexible types to files compiled without explicit nulls #23386
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
099bf33
52d7b22
3cdda29
d9f49d1
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 |
---|---|---|
|
@@ -1858,6 +1858,8 @@ object Types extends TypeUtils { | |
t | ||
case t @ SAMType(_, _) => | ||
t | ||
case ft: FlexibleType => | ||
ft.underlying.findFunctionType | ||
case _ => | ||
NoType | ||
|
||
|
@@ -3396,15 +3398,17 @@ object Types extends TypeUtils { | |
override def underlying(using Context): Type = hi | ||
|
||
def derivedFlexibleType(hi: Type)(using Context): Type = | ||
if hi eq this.hi then this else FlexibleType(hi) | ||
if hi eq this.hi then this else FlexibleType.make(hi) | ||
|
||
override def computeHash(bs: Binders): Int = doHash(bs, hi) | ||
|
||
override final def baseClasses(using Context): List[ClassSymbol] = hi.baseClasses | ||
} | ||
|
||
object FlexibleType { | ||
def apply(tp: Type)(using Context): FlexibleType = tp match { | ||
def apply(tp: Type)(using Context): FlexibleType = | ||
assert(tp.isValueType, s"Should not flexify ${tp}") | ||
tp match { | ||
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. Since we're now nullifying more complex types in Scala, do you think it's worth bringing the commented-out logic back? |
||
case ft: FlexibleType => ft | ||
case _ => | ||
// val tp1 = tp.stripNull() | ||
|
@@ -3424,6 +3428,15 @@ object Types extends TypeUtils { | |
// rule. | ||
FlexibleType(OrNull(tp), tp) | ||
} | ||
|
||
def make(tp: Type)(using Context): Type = | ||
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 we really need a separate constructor for FlexibleType? I feel we can just merge this logic into 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 separated the logic because |
||
tp match | ||
case _: FlexibleType => tp | ||
case TypeBounds(lo, hi) => TypeBounds(FlexibleType.make(lo), FlexibleType.make(hi)) | ||
case wt: WildcardType => wt.optBounds match | ||
case tb: TypeBounds => WildcardType(FlexibleType.make(tb).asInstanceOf[TypeBounds]) | ||
case _ => wt | ||
case other => FlexibleType(tp) | ||
} | ||
|
||
// --- AndType/OrType --------------------------------------------------------------- | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
byname-nullables.scala # identity() flexified | ||
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. Can you choose some tests and explain them in the PR why they are excluded? |
||
varargs.scala # Array type flexified | ||
flow-conservative.scala # .length flexified | ||
nn-basic.scala # .length flexified but trim rejected | ||
i21380c.scala # .length flexified but replaceAll rejected | ||
unsafe-scope.scala # .length flexified | ||
i17467.scala # Singleton type flexified | ||
i7883.scala # Unsure | ||
from-nullable.scala # Option argument flexified | ||
flow-in-block.scala # .length flexified | ||
array.scala # Type arugment of Array flexified | ||
flow-forward-ref.scala # .length flexified, forward reference error | ||
flow-implicitly.scala # Singleton type flexified | ||
nn.scala # Flexified elided error [!] | ||
flow-basic.scala # .length flexified | ||
|
||
unsafe-cast.scala # Array type flexified | ||
unsafe-extensions.scala # Function arguments flexified |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import unsafeNulls.Foo.* | ||
import unsafeNulls.Unsafe_1 | ||
|
||
class Inherit_1 extends Unsafe_1 { | ||
override def foo(s: String): String = s | ||
override def bar[T >: String](s: T): T = s | ||
override def bar2[T >: String | Null](s: T): T = s | ||
override def bar3[T <: Function1[String,String]](g: T) = g | ||
override def bar4[HK[_]](i: String | Null): HK[String | Null] = ??? | ||
} | ||
|
||
class Inherit_2 extends Unsafe_1 { | ||
override def foo(s: String | Null): String | Null = null | ||
override def bar[T >: String](s: T | Null): T | Null = s | ||
override def bar2[T >: String](s: T): T = s | ||
override def bar3[T <: Function1[(String|Null),(String|Null)]](g: T) = g | ||
override def bar4[HK[_]](i: String): HK[String] = ??? | ||
} | ||
|
||
class Inherit_3 extends Unsafe_1 { | ||
override def foo(s: String): String | Null = null | ||
override def bar[T >: String](s: T): T | Null = s | ||
} | ||
|
||
class Inherit_4 extends Unsafe_1 { | ||
override def foo(s: String | Null): String = "non-null string" | ||
override def bar[T >: String](s: T | Null): T = "non-null string" | ||
} | ||
|
||
case class cc() | ||
|
||
@main | ||
def Flexible_2() = | ||
val s2: String | Null = "foo" | ||
val unsafe = new Unsafe_1() | ||
val s: String = unsafe.foo(s2) | ||
unsafe.foo("") | ||
unsafe.foo(null) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package unsafeNulls | ||
|
||
class Unsafe_1 { | ||
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 need to test more scala tests.
Also, let's test not only the functions, but also constructors, members (value and type), extension methods, etc. |
||
def foo(s: String): String = { | ||
if (s == null) then "nullString" | ||
else s | ||
} | ||
def bar[T >: String](s: T): T = { | ||
??? | ||
} | ||
def bar2[T >: String | Null](s: T): T = { | ||
??? | ||
} | ||
def bar3[T <: Function1[String,String]](g: T): T = g | ||
def bar4[HK[_]](i: String): HK[String] = ??? | ||
} | ||
|
||
object Foo { | ||
def bar = "bar!" | ||
def id[T](t: T): T = t | ||
} |
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.
We need to consider other cases now:
ExprType
,AnnotatedType
,OrType
, andMatchType
(mayber? not sure).