@@ -44,7 +44,6 @@ import transform.TypeUtils._
44
44
import reporting .trace
45
45
import Nullables .{NotNullInfo , given _ }
46
46
import NullOpsDecorator ._
47
- import config .Printers .debug
48
47
49
48
object Typer {
50
49
@@ -2774,7 +2773,7 @@ class Typer extends Namer
2774
2773
*/
2775
2774
def adapt (tree : Tree , pt : Type , locked : TypeVars , tryGadtHealing : Boolean = true )(using Context ): Tree = {
2776
2775
val last = Thread .currentThread.getStackTrace()(2 ).toString;
2777
- trace/* .force */ (i " adapting (tryGadtHealing= $tryGadtHealing) $tree to $pt\n {callsite: $last} " , typr, show = true ) {
2776
+ trace(i " adapting (tryGadtHealing= $tryGadtHealing) $tree to $pt\n {callsite: $last} " , typr, show = true ) {
2778
2777
record(" adapt" )
2779
2778
adapt1(tree, pt, locked, tryGadtHealing)
2780
2779
}
@@ -2784,7 +2783,6 @@ class Typer extends Namer
2784
2783
adapt(tree, pt, ctx.typerState.ownedVars)
2785
2784
2786
2785
private def adapt1 (tree : Tree , pt : Type , locked : TypeVars , tryGadtHealing : Boolean )(using Context ): Tree = {
2787
- // assert(pt.exists && !pt.isInstanceOf[ExprType])
2788
2786
assert(pt.exists && ! pt.isInstanceOf [ExprType ] || ctx.reporter.errorsReported)
2789
2787
def methodStr = err.refStr(methPart(tree).tpe)
2790
2788
@@ -3243,19 +3241,15 @@ class Typer extends Namer
3243
3241
}
3244
3242
3245
3243
def adaptToSubType (wtp : Type ): Tree = {
3246
- debug.println(" adaptToSubType" )
3247
- debug.println(" // try converting a constant to the target type" )
3248
3244
// try converting a constant to the target type
3249
3245
val folded = ConstFold (tree, pt)
3250
3246
if (folded ne tree)
3251
3247
return adaptConstant(folded, folded.tpe.asInstanceOf [ConstantType ])
3252
3248
3253
- debug.println(" // Try to capture wildcards in type" )
3254
3249
val captured = captureWildcards(wtp)
3255
3250
if (captured `ne` wtp)
3256
3251
return readapt(tree.cast(captured))
3257
3252
3258
- debug.println(" // drop type if prototype is Unit" )
3259
3253
// drop type if prototype is Unit
3260
3254
if (pt isRef defn.UnitClass ) {
3261
3255
// local adaptation makes sure every adapted tree conforms to its pt
@@ -3265,7 +3259,6 @@ class Typer extends Namer
3265
3259
return tpd.Block (tree1 :: Nil , Literal (Constant (())))
3266
3260
}
3267
3261
3268
- debug.println(" // convert function literal to SAM closure" )
3269
3262
// convert function literal to SAM closure
3270
3263
tree match {
3271
3264
case closure(Nil , id @ Ident (nme.ANON_FUN ), _)
@@ -3283,28 +3276,28 @@ class Typer extends Namer
3283
3276
case _ =>
3284
3277
}
3285
3278
3286
- debug.println(" // try GADT approximation" )
3287
- val foo = Inferencing .approximateGADT(wtp)
3288
- debug.println(
3289
- i """
3290
- foo = $foo
3279
+ val approximation = Inferencing .approximateGADT(wtp)
3280
+ gadts.println(
3281
+ i """ GADT approximation {
3282
+ approximation = $approximation
3291
3283
pt.isInstanceOf[SelectionProto] = ${pt.isInstanceOf [SelectionProto ]}
3292
3284
ctx.gadt.nonEmpty = ${ctx.gadt.nonEmpty}
3285
+ ctx.gadt = ${ctx.gadt.debugBoundsDescription}
3293
3286
pt.isMatchedBy = ${
3294
3287
if (pt.isInstanceOf [SelectionProto ])
3295
- pt.asInstanceOf [SelectionProto ].isMatchedBy(foo ).toString
3288
+ pt.asInstanceOf [SelectionProto ].isMatchedBy(approximation ).toString
3296
3289
else
3297
3290
" <not a SelectionProto>"
3298
3291
}
3292
+ }
3299
3293
"""
3300
3294
)
3301
3295
pt match {
3302
- case pt : SelectionProto if ctx.gadt.nonEmpty && pt.isMatchedBy(foo ) =>
3303
- return tpd.Typed (tree, TypeTree (foo ))
3296
+ case pt : SelectionProto if ctx.gadt.nonEmpty && pt.isMatchedBy(approximation ) =>
3297
+ return tpd.Typed (tree, TypeTree (approximation ))
3304
3298
case _ => ;
3305
3299
}
3306
3300
3307
- debug.println(" // try an extension method in scope" )
3308
3301
// try an extension method in scope
3309
3302
pt match {
3310
3303
case SelectionProto (name, mbrType, _, _) =>
@@ -3322,33 +3315,41 @@ class Typer extends Namer
3322
3315
val app = tryExtension(using nestedCtx)
3323
3316
if (! app.isEmpty && ! nestedCtx.reporter.hasErrors) {
3324
3317
nestedCtx.typerState.commit()
3325
- debug.println(" returning ext meth in scope" )
3326
3318
return ExtMethodApply (app)
3327
3319
}
3328
3320
case _ =>
3329
3321
}
3330
3322
3331
- debug.println(" // try an implicit conversion" )
3332
3323
// try an implicit conversion
3333
3324
val prevConstraint = ctx.typerState.constraint
3334
- def recover (failure : SearchFailureType ) =
3335
- {
3336
- debug.println(" recover" )
3325
+ def recover (failure : SearchFailureType ) = {
3326
+ def canTryGADTHealing : Boolean = {
3327
+ val isDummy = tree.hasAttachment(dummyTreeOfType.IsDummyTree )
3328
+ tryGadtHealing // allow GADT healing only once to avoid a loop
3329
+ && ctx.gadt.nonEmpty // GADT healing only makes sense if there are GADT constraints present
3330
+ && ! isDummy // avoid healing a dummy tree as it can lead to an error in a very specific case
3331
+ }
3332
+
3337
3333
if (isFullyDefined(wtp, force = ForceDegree .all) &&
3338
3334
ctx.typerState.constraint.ne(prevConstraint)) readapt(tree)
3339
- // else if ({
3340
- // debug.println(i"tryGadtHealing=$tryGadtHealing && \n\tctx.gadt.nonEmpty=${ctx.gadt.nonEmpty}")
3341
- // tryGadtHealing && ctx.gadt.nonEmpty
3342
- // })
3343
- // {
3344
- // debug.println("here")
3345
- // readapt(
3346
- // tree = tpd.Typed(tree, TypeTree(Inferencing.approximateGADT(wtp))),
3347
- // shouldTryGadtHealing = false,
3348
- // )
3349
- // }
3350
- else err.typeMismatch(tree, pt, failure)
3351
- }
3335
+ else if (canTryGADTHealing) {
3336
+ // try recovering with a GADT approximation
3337
+ val nestedCtx = ctx.fresh.setNewTyperState()
3338
+ val res =
3339
+ readapt(
3340
+ tree = tpd.Typed (tree, TypeTree (Inferencing .approximateGADT(wtp))),
3341
+ shouldTryGadtHealing = false ,
3342
+ )(using nestedCtx)
3343
+ if (! nestedCtx.reporter.hasErrors) {
3344
+ // GADT recovery successful
3345
+ nestedCtx.typerState.commit()
3346
+ res
3347
+ } else {
3348
+ // otherwise fail with the error that would have been reported without the GADT recovery
3349
+ err.typeMismatch(tree, pt, failure)
3350
+ }
3351
+ } else err.typeMismatch(tree, pt, failure)
3352
+ }
3352
3353
if ctx.mode.is(Mode .ImplicitsEnabled ) && tree.typeOpt.isValueType then
3353
3354
if pt.isRef(defn.AnyValClass ) || pt.isRef(defn.ObjectClass ) then
3354
3355
ctx.error(em " the result of an implicit conversion must be more specific than $pt" , tree.sourcePos)
0 commit comments