@@ -1253,26 +1253,35 @@ class Typer extends Namer
1253
1253
if (tree.tpt.isEmpty)
1254
1254
meth1.tpe.widen match {
1255
1255
case mt : MethodType =>
1256
- pt match {
1256
+ val pt1 =
1257
+ if ctx.explicitNulls then
1258
+ pt.stripNull
1259
+ else pt
1260
+ val adaptWithUnsafeNullConver =
1261
+ ctx.explicitNulls && (
1262
+ config.Feature .enabled(nme.unsafeNulls) ||
1263
+ ctx.mode.is(Mode .UnsafeNullConversion ))
1264
+ pt1 match {
1257
1265
case SAMType (sam)
1258
- if ! defn.isFunctionType(pt) && mt <:< sam =>
1266
+ if ! defn.isFunctionType(pt1) && mt <:< sam ||
1267
+ adaptWithUnsafeNullConver && mt.isUnsafeConvertable(sam) =>
1259
1268
// SAMs of the form C[?] where C is a class cannot be conversion targets.
1260
1269
// The resulting class `class $anon extends C[?] {...}` would be illegal,
1261
1270
// since type arguments to `C`'s super constructor cannot be constructed.
1262
1271
def isWildcardClassSAM =
1263
- ! pt .classSymbol.is(Trait ) && pt .argInfos.exists(_.isInstanceOf [TypeBounds ])
1272
+ ! pt1 .classSymbol.is(Trait ) && pt1 .argInfos.exists(_.isInstanceOf [TypeBounds ])
1264
1273
val targetTpe =
1265
- if isFullyDefined(pt , ForceDegree .all) && ! isWildcardClassSAM then
1266
- pt
1267
- else if pt .isRef(defn.PartialFunctionClass ) then
1274
+ if isFullyDefined(pt1 , ForceDegree .all) && ! isWildcardClassSAM then
1275
+ pt1
1276
+ else if pt1 .isRef(defn.PartialFunctionClass ) then
1268
1277
// Replace the underspecified expected type by one based on the closure method type
1269
1278
defn.PartialFunctionOf (mt.firstParamTypes.head, mt.resultType)
1270
1279
else
1271
- report.error(ex " result type of lambda is an underspecified SAM type $pt " , tree.srcPos)
1272
- pt
1273
- if (pt .classSymbol.isOneOf(FinalOrSealed )) {
1274
- val offendingFlag = pt .classSymbol.flags & FinalOrSealed
1275
- report.error(ex " lambda cannot implement $offendingFlag ${pt .classSymbol}" , tree.srcPos)
1280
+ report.error(ex " result type of lambda is an underspecified SAM type $pt1 " , tree.srcPos)
1281
+ pt1
1282
+ if (pt1 .classSymbol.isOneOf(FinalOrSealed )) {
1283
+ val offendingFlag = pt1 .classSymbol.flags & FinalOrSealed
1284
+ report.error(ex " lambda cannot implement $offendingFlag ${pt1 .classSymbol}" , tree.srcPos)
1276
1285
}
1277
1286
TypeTree (targetTpe)
1278
1287
case _ =>
@@ -3434,13 +3443,23 @@ class Typer extends Namer
3434
3443
return tpd.Block (tree1 :: Nil , Literal (Constant (())))
3435
3444
}
3436
3445
3446
+ val adaptWithUnsafeNullConver =
3447
+ ctx.explicitNulls && (
3448
+ config.Feature .enabled(nme.unsafeNulls) ||
3449
+ ctx.mode.is(Mode .UnsafeNullConversion ))
3450
+
3437
3451
// convert function literal to SAM closure
3438
3452
tree match {
3439
3453
case closure(Nil , id @ Ident (nme.ANON_FUN ), _)
3440
3454
if defn.isFunctionType(wtp) && ! defn.isFunctionType(pt) =>
3441
- pt match {
3455
+ val pt1 =
3456
+ if ctx.explicitNulls then
3457
+ pt.stripNull
3458
+ else pt
3459
+ pt1 match {
3442
3460
case SAMType (sam)
3443
- if wtp <:< sam.toFunctionType() =>
3461
+ if wtp <:< sam.toFunctionType() ||
3462
+ (adaptWithUnsafeNullConver && wtp.isUnsafeConvertable(sam.toFunctionType())) =>
3444
3463
// was ... && isFullyDefined(pt, ForceDegree.flipBottom)
3445
3464
// but this prevents case blocks from implementing polymorphic partial functions,
3446
3465
// since we do not know the result parameter a priori. Have to wait until the
@@ -3509,12 +3528,11 @@ class Typer extends Namer
3509
3528
}
3510
3529
}
3511
3530
3512
- def tryUnsafeNullConver (fail : => Tree ): Tree =
3531
+ def tryUnsafeNullConver (fail : => Tree )( using Context ) : Tree =
3513
3532
// If explicitNulls and unsafeNulls are enabled, and
3514
- if ctx.explicitNulls && config.Feature .enabled(nme.unsafeNulls) &&
3515
- tree.tpe.isUnsafeConvertable(pt) then {
3516
- tree.cast(pt)
3517
- }
3533
+ if ctx.mode.is(Mode .UnsafeNullConversion ) && pt.isValueType &&
3534
+ tree.tpe.isUnsafeConvertable(pt)
3535
+ then tree.cast(pt)
3518
3536
else fail
3519
3537
3520
3538
def cannotFind (failure : SearchFailure ) =
@@ -3527,21 +3545,25 @@ class Typer extends Namer
3527
3545
tree
3528
3546
else recover(failure.reason)
3529
3547
3530
- if ctx.mode.is(Mode .ImplicitsEnabled ) && tree.typeOpt.isValueType then
3531
- if pt.isRef(defn.AnyValClass ) || pt.isRef(defn.ObjectClass ) then
3532
- ctx.error(em " the result of an implicit conversion must be more specific than $pt" , tree.sourcePos)
3533
- val searchCtx = if config.Feature .enabled(nme.unsafeNulls)
3534
- then ctx.addMode(Mode .UnsafeNullConversion )
3535
- else ctx
3536
- tree.tpe match {
3537
- case OrNull (tpe1) if ctx.explicitNulls && config.Feature .enabled(nme.unsafeNulls) =>
3538
- searchTree(tree.cast(tpe1)) { _ =>
3539
- searchTree(tree)(failure => tryUnsafeNullConver(cannotFind(failure)))(using searchCtx)
3540
- }(using searchCtx)
3541
- case _ =>
3542
- searchTree(tree)(failure => tryUnsafeNullConver(cannotFind(failure)))(using searchCtx)
3543
- }
3544
- else tryUnsafeNullConver(recover(NoMatchingImplicits ))
3548
+ val searchCtx =
3549
+ if ctx.explicitNulls && config.Feature .enabled(nme.unsafeNulls) then
3550
+ ctx.addMode(Mode .UnsafeNullConversion )
3551
+ else ctx
3552
+
3553
+ inContext(searchCtx) {
3554
+ if ctx.mode.is(Mode .ImplicitsEnabled ) && tree.typeOpt.isValueType then
3555
+ if pt.isRef(defn.AnyValClass ) || pt.isRef(defn.ObjectClass ) then
3556
+ report.error(em " the result of an implicit conversion must be more specific than $pt" , tree.srcPos)
3557
+ tree.tpe match {
3558
+ case OrNull (tpe1) if ctx.explicitNulls && config.Feature .enabled(nme.unsafeNulls) =>
3559
+ searchTree(tree.cast(tpe1)) { _ =>
3560
+ searchTree(tree)(failure => tryUnsafeNullConver(cannotFind(failure)))
3561
+ }
3562
+ case _ =>
3563
+ searchTree(tree)(failure => tryUnsafeNullConver(cannotFind(failure)))
3564
+ }
3565
+ else tryUnsafeNullConver(recover(NoMatchingImplicits ))
3566
+ }
3545
3567
}
3546
3568
3547
3569
def adaptType (tp : Type ): Tree = {
0 commit comments