Skip to content

Commit f0c05cf

Browse files
committed
Fix type parameter forwarding
We failed to take into account that a parameter might be forwarded to several types, in which case these types need to be conjoined. This led to a failure to compile the collection strawman unless forwarding was disabled.
1 parent 609e40e commit f0c05cf

File tree

1 file changed

+61
-69
lines changed

1 file changed

+61
-69
lines changed

compiler/src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 61 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -321,73 +321,11 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
321321
}
322322
}
323323

324-
/** If we have member definitions
325-
*
326-
* type argSym v= from
327-
* type from v= to
328-
*
329-
* where the variances of both alias are the same, then enter a new definition
330-
*
331-
* type argSym v= to
332-
*
333-
* unless a definition for `argSym` already exists in the current scope.
334-
*/
335-
def forwardRef(argSym: Symbol, from: Symbol, to: TypeBounds, cls: ClassSymbol, decls: Scope) =
336-
argSym.info match {
337-
case info @ TypeBounds(lo2 @ TypeRef(_: ThisType, name), hi2) =>
338-
if (name == from.name &&
339-
(lo2 eq hi2) &&
340-
info.variance == to.variance &&
341-
!decls.lookup(argSym.name).exists &&
342-
!ctx.settings.YsuppressParamForwarding.value) {
343-
// println(s"short-circuit ${argSym.name} was: ${argSym.info}, now: $to")
344-
enterArgBinding(argSym, to, cls, decls)
345-
}
346-
case _ =>
347-
}
348-
349-
350324
/** Normalize a list of parent types of class `cls` that may contain refinements
351325
* to a list of typerefs referring to classes, by converting all refinements to member
352326
* definitions in scope `decls`. Can add members to `decls` as a side-effect.
353327
*/
354328
def normalizeToClassRefs(parents: List[Type], cls: ClassSymbol, decls: Scope): List[TypeRef] = {
355-
356-
/** If we just entered the type argument binding
357-
*
358-
* type From = To
359-
*
360-
* and there is a type argument binding in a parent in `prefs` of the form
361-
*
362-
* type X = From
363-
*
364-
* then also add the binding
365-
*
366-
* type X = To
367-
*
368-
* to the current scope, provided (1) variances of both aliases are the same, and
369-
* (2) X is not yet defined in current scope. This "short-circuiting" prevents
370-
* long chains of aliases which would have to be traversed in type comparers.
371-
*
372-
* Note: Test i1401.scala shows that `forwardRefs` is also necessary
373-
* for typechecking in the case where self types refer to type parameters
374-
* that are upper-bounded by subclass instances.
375-
*/
376-
def forwardRefs(from: Symbol, to: Type, prefs: List[TypeRef]) = to match {
377-
case to @ TypeBounds(lo1, hi1) if lo1 eq hi1 =>
378-
for (pref <- prefs) {
379-
def forward()(implicit ctx: Context): Unit =
380-
for (argSym <- pref.decls)
381-
if (argSym is BaseTypeArg)
382-
forwardRef(argSym, from, to, cls, decls)
383-
pref.info match {
384-
case info: TempClassInfo => info.addSuspension(implicit ctx => forward())
385-
case _ => forward()
386-
}
387-
}
388-
case _ =>
389-
}
390-
391329
// println(s"normalizing $parents of $cls in ${cls.owner}") // !!! DEBUG
392330

393331
// A map consolidating all refinements arising from parent type parameters
@@ -430,16 +368,70 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
430368
s"redefinition of ${decls.lookup(name).debugString} in ${cls.showLocated}")
431369
enterArgBinding(formals(name), refinedInfo, cls, decls)
432370
}
433-
// Forward definitions in super classes that have one of the refined parameters
434-
// as aliases directly to the refined info.
435-
// Note that this cannot be fused with the previous loop because we now
436-
// assume that all arguments have been entered in `decls`.
437-
refinements foreachBinding { (name, refinedInfo) =>
438-
forwardRefs(formals(name), refinedInfo, parentRefs)
439-
}
371+
372+
if (!ctx.settings.YsuppressParamForwarding.value)
373+
forwardParamBindings(parentRefs, refinements, cls, decls)
374+
440375
parentRefs
441376
}
442377

378+
/** Forward parameter bindings in baseclasses to argument types of
379+
* class `cls` if possible.
380+
* If there have member definitions
381+
*
382+
* type param v= middle
383+
* type middle v= to
384+
*
385+
* where the variances of both alias are the same, then enter a new definition
386+
*
387+
* type param v= to
388+
*
389+
* If multiple forwarders would be generated, join their `to` types with an `&`.
390+
*
391+
* @param cls The class for which parameter bindings should be forwarded
392+
* @param decls Its scope
393+
* @param parentRefs The parent type references of `cls`
394+
* @param paramBindings The type parameter bindings generated for `cls`
395+
*
396+
*/
397+
def forwardParamBindings(parentRefs: List[TypeRef],
398+
paramBindings: SimpleMap[TypeName, Type],
399+
cls: ClassSymbol, decls: Scope)(implicit ctx: Context) = {
400+
401+
def forwardRef(argSym: Symbol, from: TypeName, to: TypeAlias) = argSym.info match {
402+
case info @ TypeAlias(TypeRef(_: ThisType, `from`)) if info.variance == to.variance =>
403+
val existing = decls.lookup(argSym.name)
404+
if (existing.exists) existing.info = existing.info & to
405+
else enterArgBinding(argSym, to, cls, decls)
406+
case _ =>
407+
}
408+
409+
def forwardRefs(from: TypeName, to: Type) = to match {
410+
case to: TypeAlias =>
411+
for (pref <- parentRefs) {
412+
def forward()(implicit ctx: Context): Unit =
413+
for (argSym <- pref.decls)
414+
if (argSym is BaseTypeArg) forwardRef(argSym, from, to)
415+
pref.info match {
416+
case info: TempClassInfo => info.addSuspension(implicit ctx => forward())
417+
case _ => forward()
418+
}
419+
}
420+
case _ =>
421+
}
422+
423+
paramBindings.foreachBinding(forwardRefs)
424+
}
425+
426+
/** Used only for debugging: All BaseTypeArg definitions in
427+
* `cls` and all its base classes.
428+
*/
429+
def allBaseTypeArgs(cls: ClassSymbol)(implicit ctx: Context) =
430+
for { bc <- cls.baseClasses
431+
sym <- bc.info.decls.toList
432+
if sym.is(BaseTypeArg)
433+
} yield sym
434+
443435
/** An argument bounds violation is a triple consisting of
444436
* - the argument tree
445437
* - a string "upper" or "lower" indicating which bound is violated

0 commit comments

Comments
 (0)