@@ -47,27 +47,40 @@ object ProtoTypes {
47
47
necessarySubType(tpn, pt) || tpn.isValueSubType(pt) || viewExists(tpn, pt)
48
48
49
49
/** Test compatibility after normalization.
50
- * Do this in a fresh typerstate unless `keepConstraint` is true .
50
+ * If `keepConstraint` is false, the current constraint set will not be modified by this call .
51
51
*/
52
- def normalizedCompatible (tp : Type , pt : Type , keepConstraint : Boolean )(using Context ): Boolean = {
53
- def testCompat (using Context ): Boolean = {
52
+ def normalizedCompatible (tp : Type , pt : Type , keepConstraint : Boolean )(using Context ): Boolean =
53
+
54
+ def testCompat (using Context ): Boolean =
54
55
val normTp = normalize(tp, pt)
55
56
isCompatible(normTp, pt) || pt.isRef(defn.UnitClass ) && normTp.isParameterless
56
- }
57
- if ( keepConstraint)
58
- tp.widenSingleton match {
57
+
58
+ if keepConstraint then
59
+ tp.widenSingleton match
59
60
case poly : PolyType =>
60
- // We can't keep the constraint in this case, since we have to add type parameters
61
- // to it, but there's no place to associate them with type variables.
62
- // So we'd get a "inconsistent: no typevars were added to committable constraint"
63
- // assertion failure in `constrained`. To do better, we'd have to change the
64
- // constraint handling architecture so that some type parameters are committable
65
- // and others are not. But that's a whole different ballgame.
66
- normalizedCompatible(tp, pt, keepConstraint = false )
61
+ val newctx = ctx.fresh.setNewTyperState()
62
+ val result = testCompat(using newctx)
63
+ typr.println(
64
+ i """ normalizedCompatible for $poly, $pt = $result
65
+ |constraint was: ${ctx.typerState.constraint}
66
+ |constraint now: ${newctx.typerState.constraint}""" )
67
+ if result
68
+ && (ctx.typerState.constraint ne newctx.typerState.constraint)
69
+ && {
70
+ val existingVars = ctx.typerState.uninstVars.toSet
71
+ newctx.typerState.uninstVars.forall(existingVars.contains)
72
+ }
73
+ then newctx.typerState.commit()
74
+ // If the new constrait contains fresh type variables we cannot keep it,
75
+ // since those type variables are not instantiated anywhere in the source.
76
+ // See pos/i6682a.scala for a test case. See pos/11243.scala and pos/i5773b.scala
77
+ // for tests where it matters that we keep the constraint otherwise.
78
+ // TODO: A better solution would clean the new constraint, so that it "avoids"
79
+ // the problematic type variables. But we have not implemented such an algorithm yet.
80
+ result
67
81
case _ => testCompat
68
- }
69
82
else explore(testCompat)
70
- }
83
+ end normalizedCompatible
71
84
72
85
private def disregardProto (pt : Type )(using Context ): Boolean =
73
86
pt.dealias.isRef(defn.UnitClass )
@@ -79,10 +92,18 @@ object ProtoTypes {
79
92
val savedConstraint = ctx.typerState.constraint
80
93
val res = pt.widenExpr match {
81
94
case pt : FunProto =>
82
- mt match {
83
- case mt : MethodType => constrainResult(resultTypeApprox(mt), pt.resultType)
95
+ mt match
96
+ case mt : MethodType =>
97
+ constrainResult(resultTypeApprox(mt), pt.resultType)
98
+ && {
99
+ if pt.constrainResultDeep
100
+ && mt.isImplicitMethod == (pt.applyKind == ApplyKind .Using )
101
+ then
102
+ pt.args.lazyZip(mt.paramInfos).forall((arg, paramInfo) =>
103
+ pt.typedArg(arg, paramInfo).tpe <:< paramInfo)
104
+ else true
105
+ }
84
106
case _ => true
85
- }
86
107
case _ : ValueTypeOrProto if ! disregardProto(pt) =>
87
108
necessarilyCompatible(mt, pt)
88
109
case pt : WildcardType if pt.optBounds.exists =>
@@ -123,6 +144,7 @@ object ProtoTypes {
123
144
abstract case class IgnoredProto (ignored : Type ) extends CachedGroundType with MatchAlways :
124
145
override def revealIgnored = ignored
125
146
override def deepenProto (using Context ): Type = ignored
147
+ override def deepenProtoTrans (using Context ): Type = ignored.deepenProtoTrans
126
148
127
149
override def computeHash (bs : Hashable .Binders ): Int = doHash(bs, ignored)
128
150
@@ -202,7 +224,12 @@ object ProtoTypes {
202
224
def map (tm : TypeMap )(using Context ): SelectionProto = derivedSelectionProto(name, tm(memberProto), compat)
203
225
def fold [T ](x : T , ta : TypeAccumulator [T ])(using Context ): T = ta(x, memberProto)
204
226
205
- override def deepenProto (using Context ): SelectionProto = derivedSelectionProto(name, memberProto.deepenProto, compat)
227
+ override def deepenProto (using Context ): SelectionProto =
228
+ derivedSelectionProto(name, memberProto.deepenProto, compat)
229
+
230
+ override def deepenProtoTrans (using Context ): SelectionProto =
231
+ derivedSelectionProto(name, memberProto.deepenProtoTrans, compat)
232
+
206
233
override def computeHash (bs : Hashable .Binders ): Int = {
207
234
val delta = (if (compat eq NoViewsAllowed ) 1 else 0 ) | (if (privateOK) 2 else 0 )
208
235
addDelta(doHash(bs, name, memberProto), delta)
@@ -276,9 +303,21 @@ object ProtoTypes {
276
303
/** A prototype for expressions that appear in function position
277
304
*
278
305
* [](args): resultType
306
+ *
307
+ * @param args The untyped arguments to which the function is applied
308
+ * @param resType The expeected result type
309
+ * @param typer The typer to use for typing the arguments
310
+ * @param applyKind The kind of application (regular/using/tupled infix operand)
311
+ * @param state The state object to use for tracking the changes to this prototype
312
+ * @param constrainResultDeep
313
+ * A flag to indicate that constrainResult on this prototype
314
+ * should typecheck and compare the arguments.
279
315
*/
280
- case class FunProto (args : List [untpd.Tree ], resType : Type )(typer : Typer ,
281
- override val applyKind : ApplyKind , state : FunProtoState = new FunProtoState )(using protoCtx : Context )
316
+ case class FunProto (args : List [untpd.Tree ], resType : Type )(
317
+ typer : Typer ,
318
+ override val applyKind : ApplyKind ,
319
+ state : FunProtoState = new FunProtoState ,
320
+ val constrainResultDeep : Boolean = false )(using protoCtx : Context )
282
321
extends UncachedGroundType with ApplyingProto with FunOrPolyProto {
283
322
override def resultType (using Context ): Type = resType
284
323
@@ -290,9 +329,17 @@ object ProtoTypes {
290
329
typer.isApplicableType(tp, args, resultType, keepConstraint && ! args.exists(isPoly))
291
330
}
292
331
293
- def derivedFunProto (args : List [untpd.Tree ] = this .args, resultType : Type , typer : Typer = this .typer): FunProto =
294
- if ((args eq this .args) && (resultType eq this .resultType) && (typer eq this .typer)) this
295
- else new FunProto (args, resultType)(typer, applyKind)
332
+ def derivedFunProto (
333
+ args : List [untpd.Tree ] = this .args,
334
+ resultType : Type = this .resultType,
335
+ typer : Typer = this .typer,
336
+ constrainResultDeep : Boolean = this .constrainResultDeep): FunProto =
337
+ if (args eq this .args)
338
+ && (resultType eq this .resultType)
339
+ && (typer eq this .typer)
340
+ && constrainResultDeep == this .constrainResultDeep
341
+ then this
342
+ else new FunProto (args, resultType)(typer, applyKind, constrainResultDeep = constrainResultDeep)
296
343
297
344
/** @return True if all arguments have types.
298
345
*/
@@ -419,7 +466,11 @@ object ProtoTypes {
419
466
def fold [T ](x : T , ta : TypeAccumulator [T ])(using Context ): T =
420
467
ta(ta.foldOver(x, typedArgs().tpes), resultType)
421
468
422
- override def deepenProto (using Context ): FunProto = derivedFunProto(args, resultType.deepenProto, typer)
469
+ override def deepenProto (using Context ): FunProto =
470
+ derivedFunProto(args, resultType.deepenProto)
471
+
472
+ override def deepenProtoTrans (using Context ): FunProto =
473
+ derivedFunProto(args, resultType.deepenProtoTrans, constrainResultDeep = true )
423
474
424
475
override def withContext (newCtx : Context ): ProtoType =
425
476
if newCtx `eq` protoCtx then this
@@ -472,7 +523,11 @@ object ProtoTypes {
472
523
def fold [T ](x : T , ta : TypeAccumulator [T ])(using Context ): T =
473
524
ta(ta(x, argType), resultType)
474
525
475
- override def deepenProto (using Context ): ViewProto = derivedViewProto(argType, resultType.deepenProto)
526
+ override def deepenProto (using Context ): ViewProto =
527
+ derivedViewProto(argType, resultType.deepenProto)
528
+
529
+ override def deepenProtoTrans (using Context ): ViewProto =
530
+ derivedViewProto(argType, resultType.deepenProtoTrans)
476
531
}
477
532
478
533
class CachedViewProto (argType : Type , resultType : Type ) extends ViewProto (argType, resultType) {
@@ -522,7 +577,11 @@ object ProtoTypes {
522
577
def fold [T ](x : T , ta : TypeAccumulator [T ])(using Context ): T =
523
578
ta(ta.foldOver(x, targs.tpes), resultType)
524
579
525
- override def deepenProto (using Context ): PolyProto = derivedPolyProto(targs, resultType.deepenProto)
580
+ override def deepenProto (using Context ): PolyProto =
581
+ derivedPolyProto(targs, resultType.deepenProto)
582
+
583
+ override def deepenProtoTrans (using Context ): PolyProto =
584
+ derivedPolyProto(targs, resultType.deepenProtoTrans)
526
585
}
527
586
528
587
/** A prototype for expressions [] that are known to be functions:
0 commit comments