@@ -50,6 +50,42 @@ trait Infer extends Checkable {
50
50
formals1
51
51
}
52
52
53
+ // @requires sam == samOf(samTp)
54
+ def instantiateSamFromFunction (funTp : Type , samTp : Type , sam : Symbol ) = {
55
+ val samClassSym = samTp.typeSymbol
56
+
57
+ // the unknowns
58
+ val tparams = samClassSym.typeParams
59
+
60
+ if (tparams.isEmpty) samTp
61
+ else {
62
+ // ... as typevars
63
+ val tvars = tparams map freshVar
64
+
65
+ // we're trying to fully define the type arguments for this type constructor
66
+ val samTyCon = samClassSym.typeConstructor
67
+
68
+ val ptVars = appliedType(samTyCon, tvars)
69
+
70
+ // carry over info from pt
71
+ ptVars <:< samTp
72
+
73
+ val samInfoWithTVars = ptVars.memberInfo(sam)
74
+
75
+ // use function type subtyping, not method type subtyping (the latter is invariant in argument types)
76
+ funTp <:< functionType(samInfoWithTVars.paramTypes, samInfoWithTVars.finalResultType)
77
+
78
+ val variances = tparams map varianceInType(sam.info)
79
+
80
+ // solve constraints tracked by tvars
81
+ val targs = solvedTypes(tvars, tparams, variances, upper = false , lubDepth(sam.info :: Nil ))
82
+
83
+ debuglog(s " sam infer: $samTp --> ${appliedType(samTyCon, targs)} by ${funTp} <:< $samInfoWithTVars --> $targs for $tparams" )
84
+
85
+ appliedType(samTyCon, targs)
86
+ }
87
+ }
88
+
53
89
/** Sorts the alternatives according to the given comparison function.
54
90
* Returns a list containing the best alternative as well as any which
55
91
* the best fails to improve upon.
@@ -103,9 +139,9 @@ trait Infer extends Checkable {
103
139
finally excludedVars -= tv
104
140
}
105
141
def apply (tp : Type ): Type = tp match {
106
- case WildcardType | BoundedWildcardType (_) | NoType => throw new NoInstance (" undetermined type" )
107
- case tv : TypeVar if ! tv.untouchable => applyTypeVar(tv)
108
- case _ => mapOver(tp)
142
+ case _ : ProtoType | NoType => throw new NoInstance (" undetermined type" )
143
+ case tv : TypeVar if ! tv.untouchable => applyTypeVar(tv)
144
+ case _ => mapOver(tp)
109
145
}
110
146
}
111
147
@@ -115,13 +151,13 @@ trait Infer extends Checkable {
115
151
/** Is type fully defined, i.e. no embedded anytypes or wildcards in it?
116
152
*/
117
153
private [typechecker] def isFullyDefined (tp : Type ): Boolean = tp match {
118
- case WildcardType | BoundedWildcardType (_) | NoType => false
119
- case NoPrefix | ThisType (_) | ConstantType (_) => true
120
- case TypeRef (pre, _, args) => isFullyDefined(pre) && (args forall isFullyDefined)
121
- case SingleType (pre, _) => isFullyDefined(pre)
122
- case RefinedType (ts, _) => ts forall isFullyDefined
123
- case TypeVar (_, constr) if constr.inst == NoType => false
124
- case _ => falseIfNoInstance( { instantiate(tp) ; true })
154
+ case _ : ProtoType | NoType => false
155
+ case NoPrefix | ThisType (_) | ConstantType (_) => true
156
+ case TypeRef (pre, _, args) => isFullyDefined(pre) && (args forall isFullyDefined)
157
+ case SingleType (pre, _) => isFullyDefined(pre)
158
+ case RefinedType (ts, _) => ts forall isFullyDefined
159
+ case TypeVar (_, constr) if constr.inst == NoType => false
160
+ case _ => falseIfNoInstance { instantiate(tp); true }
125
161
}
126
162
127
163
/** Solve constraint collected in types `tvars`.
@@ -151,25 +187,7 @@ trait Infer extends Checkable {
151
187
case _ => tp
152
188
}
153
189
154
- /** Automatically perform the following conversions on expression types:
155
- * A method type becomes the corresponding function type.
156
- * A nullary method type becomes its result type.
157
- * Implicit parameters are skipped.
158
- * This method seems to be performance critical.
159
- */
160
- def normalize (tp : Type ): Type = tp match {
161
- case PolyType (_, restpe) =>
162
- logResult(sm """ |Normalizing PolyType in infer:
163
- | was: $restpe
164
- | now """ )(normalize(restpe))
165
- case mt @ MethodType (_, restpe) if mt.isImplicit => normalize(restpe)
166
- case mt @ MethodType (_, restpe) if ! mt.isDependentMethodType =>
167
- if (phase.erasedTypes) FunctionClass (mt.params.length).tpe
168
- else functionType(mt.paramTypes, normalize(restpe))
169
- case NullaryMethodType (restpe) => normalize(restpe)
170
- case ExistentialType (tparams, qtpe) => newExistentialType(tparams, normalize(qtpe))
171
- case _ => tp // @MAT aliases already handled by subtyping
172
- }
190
+
173
191
174
192
private lazy val stdErrorClass = rootMirror.RootClass .newErrorClass(tpnme.ERROR )
175
193
private lazy val stdErrorValue = stdErrorClass.newErrorValue(nme.ERROR )
@@ -297,11 +315,11 @@ trait Infer extends Checkable {
297
315
&& isCompatible(tp, dropByName(pt))
298
316
)
299
317
def isCompatibleSam (tp : Type , pt : Type ): Boolean = (definitions.isFunctionType(tp) || tp.isInstanceOf [MethodType ] || tp.isInstanceOf [PolyType ]) && {
300
- val samFun = typer. samToFunctionType(pt)
318
+ val samFun = samToFunctionType(pt)
301
319
(samFun ne NoType ) && isCompatible(tp, samFun)
302
320
}
303
321
304
- val tp1 = normalize (tp)
322
+ val tp1 = methodToExpressionTp (tp)
305
323
306
324
( (tp1 weak_<:< pt)
307
325
|| isCoercible(tp1, pt)
@@ -344,9 +362,8 @@ trait Infer extends Checkable {
344
362
tparam.tpe
345
363
}
346
364
val tp1 = tp map {
347
- case WildcardType => addTypeParam(TypeBounds .empty)
348
- case BoundedWildcardType (bounds) => addTypeParam(bounds)
349
- case t => t
365
+ case pt : ProtoType => addTypeParam(pt.toBounds)
366
+ case t => t
350
367
}
351
368
if (tp eq tp1) tp
352
369
else existentialAbstraction(tparams.reverse, tp1)
@@ -359,25 +376,27 @@ trait Infer extends Checkable {
359
376
* conforms to `pt`, return null.
360
377
*/
361
378
private def exprTypeArgs (tvars : List [TypeVar ], tparams : List [Symbol ], restpe : Type , pt : Type , useWeaklyCompatible : Boolean ): List [Type ] = {
362
- def restpeInst = restpe.instantiateTypeParams(tparams, tvars)
363
- def conforms = if (useWeaklyCompatible) isWeaklyCompatible(restpeInst, pt) else isCompatible(restpeInst, pt)
364
- // If the restpe is an implicit method, and the expected type is fully defined
365
- // optimize type variables wrt to the implicit formals only; ignore the result type.
366
- // See test pos/jesper.scala
367
- def variance = restpe match {
368
- case mt : MethodType if mt.isImplicit && isFullyDefined(pt) => MethodType (mt.params, AnyTpe )
369
- case _ => restpe
370
- }
371
- def solve () = solvedTypes(tvars, tparams, tparams map varianceInType(variance), upper = false , lubDepth(restpe :: pt :: Nil ))
379
+ val resTpVars = restpe.instantiateTypeParams(tparams, tvars)
372
380
373
- if (conforms ) {
381
+ if (if (useWeaklyCompatible) isWeaklyCompatible(resTpVars, pt) else isCompatible(resTpVars, pt) ) {
374
382
// If conforms has just solved a tvar as a singleton type against pt, then we need to
375
383
// prevent it from being widened later by adjustTypeArgs
376
384
tvars.foreach(_.constr.stopWideningIfPrecluded)
377
- try solve() catch { case _ : NoInstance => null }
385
+
386
+ // If the restpe is an implicit method, and the expected type is fully defined
387
+ // optimize type variables wrt to the implicit formals only; ignore the result type.
388
+ // See test pos/jesper.scala
389
+ val variance = restpe match {
390
+ case mt : MethodType if mt.isImplicit && isFullyDefined(pt) => MethodType (mt.params, AnyTpe )
391
+ case _ => restpe
392
+ }
393
+
394
+ try solvedTypes(tvars, tparams, tparams map varianceInType(variance), upper = false , lubDepth(restpe :: pt :: Nil ))
395
+ catch { case _ : NoInstance => null }
378
396
} else
379
397
null
380
398
}
399
+
381
400
/** Overload which allocates fresh type vars.
382
401
* The other one exists because apparently inferExprInstance needs access to the typevars
383
402
* after the call, and it's wasteful to return a tuple and throw it away almost every time.
0 commit comments