Skip to content

Commit 27be018

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 aa328a9 commit 27be018

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
@@ -352,73 +352,11 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
352352
}
353353
}
354354

355-
/** If we have member definitions
356-
*
357-
* type argSym v= from
358-
* type from v= to
359-
*
360-
* where the variances of both alias are the same, then enter a new definition
361-
*
362-
* type argSym v= to
363-
*
364-
* unless a definition for `argSym` already exists in the current scope.
365-
*/
366-
def forwardRef(argSym: Symbol, from: Symbol, to: TypeBounds, cls: ClassSymbol, decls: Scope) =
367-
argSym.info match {
368-
case info @ TypeBounds(lo2 @ TypeRef(_: ThisType, name), hi2) =>
369-
if (name == from.name &&
370-
(lo2 eq hi2) &&
371-
info.variance == to.variance &&
372-
!decls.lookup(argSym.name).exists &&
373-
!ctx.settings.YsuppressParamForwarding.value) {
374-
// println(s"short-circuit ${argSym.name} was: ${argSym.info}, now: $to")
375-
enterArgBinding(argSym, to, cls, decls)
376-
}
377-
case _ =>
378-
}
379-
380-
381355
/** Normalize a list of parent types of class `cls` that may contain refinements
382356
* to a list of typerefs referring to classes, by converting all refinements to member
383357
* definitions in scope `decls`. Can add members to `decls` as a side-effect.
384358
*/
385359
def normalizeToClassRefs(parents: List[Type], cls: ClassSymbol, decls: Scope): List[TypeRef] = {
386-
387-
/** If we just entered the type argument binding
388-
*
389-
* type From = To
390-
*
391-
* and there is a type argument binding in a parent in `prefs` of the form
392-
*
393-
* type X = From
394-
*
395-
* then also add the binding
396-
*
397-
* type X = To
398-
*
399-
* to the current scope, provided (1) variances of both aliases are the same, and
400-
* (2) X is not yet defined in current scope. This "short-circuiting" prevents
401-
* long chains of aliases which would have to be traversed in type comparers.
402-
*
403-
* Note: Test i1401.scala shows that `forwardRefs` is also necessary
404-
* for typechecking in the case where self types refer to type parameters
405-
* that are upper-bounded by subclass instances.
406-
*/
407-
def forwardRefs(from: Symbol, to: Type, prefs: List[TypeRef]) = to match {
408-
case to @ TypeBounds(lo1, hi1) if lo1 eq hi1 =>
409-
for (pref <- prefs) {
410-
def forward()(implicit ctx: Context): Unit =
411-
for (argSym <- pref.decls)
412-
if (argSym is BaseTypeArg)
413-
forwardRef(argSym, from, to, cls, decls)
414-
pref.info match {
415-
case info: TempClassInfo => info.addSuspension(implicit ctx => forward())
416-
case _ => forward()
417-
}
418-
}
419-
case _ =>
420-
}
421-
422360
// println(s"normalizing $parents of $cls in ${cls.owner}") // !!! DEBUG
423361

424362
// A map consolidating all refinements arising from parent type parameters
@@ -461,16 +399,70 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
461399
s"redefinition of ${decls.lookup(name).debugString} in ${cls.showLocated}")
462400
enterArgBinding(formals(name), refinedInfo, cls, decls)
463401
}
464-
// Forward definitions in super classes that have one of the refined parameters
465-
// as aliases directly to the refined info.
466-
// Note that this cannot be fused with the previous loop because we now
467-
// assume that all arguments have been entered in `decls`.
468-
refinements foreachBinding { (name, refinedInfo) =>
469-
forwardRefs(formals(name), refinedInfo, parentRefs)
470-
}
402+
403+
if (!ctx.settings.YsuppressParamForwarding.value)
404+
forwardParamBindings(parentRefs, refinements, cls, decls)
405+
471406
parentRefs
472407
}
473408

409+
/** Forward parameter bindings in baseclasses to argument types of
410+
* class `cls` if possible.
411+
* If there have member definitions
412+
*
413+
* type param v= middle
414+
* type middle v= to
415+
*
416+
* where the variances of both alias are the same, then enter a new definition
417+
*
418+
* type param v= to
419+
*
420+
* If multiple forwarders would be generated, join their `to` types with an `&`.
421+
*
422+
* @param cls The class for which parameter bindings should be forwarded
423+
* @param decls Its scope
424+
* @param parentRefs The parent type references of `cls`
425+
* @param paramBindings The type parameter bindings generated for `cls`
426+
*
427+
*/
428+
def forwardParamBindings(parentRefs: List[TypeRef],
429+
paramBindings: SimpleMap[TypeName, Type],
430+
cls: ClassSymbol, decls: Scope)(implicit ctx: Context) = {
431+
432+
def forwardRef(argSym: Symbol, from: TypeName, to: TypeAlias) = argSym.info match {
433+
case info @ TypeAlias(TypeRef(_: ThisType, `from`)) if info.variance == to.variance =>
434+
val existing = decls.lookup(argSym.name)
435+
if (existing.exists) existing.info = existing.info & to
436+
else enterArgBinding(argSym, to, cls, decls)
437+
case _ =>
438+
}
439+
440+
def forwardRefs(from: TypeName, to: Type) = to match {
441+
case to: TypeAlias =>
442+
for (pref <- parentRefs) {
443+
def forward()(implicit ctx: Context): Unit =
444+
for (argSym <- pref.decls)
445+
if (argSym is BaseTypeArg) forwardRef(argSym, from, to)
446+
pref.info match {
447+
case info: TempClassInfo => info.addSuspension(implicit ctx => forward())
448+
case _ => forward()
449+
}
450+
}
451+
case _ =>
452+
}
453+
454+
paramBindings.foreachBinding(forwardRefs)
455+
}
456+
457+
/** Used only for debugging: All BaseTypeArg definitions in
458+
* `cls` and all its base classes.
459+
*/
460+
def allBaseTypeArgs(cls: ClassSymbol)(implicit ctx: Context) =
461+
for { bc <- cls.baseClasses
462+
sym <- bc.info.decls.toList
463+
if sym.is(BaseTypeArg)
464+
} yield sym
465+
474466
/** An argument bounds violation is a triple consisting of
475467
* - the argument tree
476468
* - a string "upper" or "lower" indicating which bound is violated

0 commit comments

Comments
 (0)