From 82a6d6f52065ae39a0a162f95e5002a6ab26cc55 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Fri, 2 Oct 2015 23:25:30 +0200 Subject: TypeAssigner#avoid: do not lose type parameters when the base type changes. Fixes #741. --- src/dotty/tools/dotc/typer/TypeAssigner.scala | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala index 22c062243..7225ede14 100644 --- a/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -87,13 +87,28 @@ trait TypeAssigner { case _ => mapOver(tp) } - case tp: RefinedType => - val tp1 @ RefinedType(parent1, _) = mapOver(tp) - if (toAvoid(tp1.refinedInfo) && variance > 0) { - typr.println(s"dropping refinement from $tp1") - parent1 + case tp @ RefinedType(parent, name) if variance > 0 => + // The naive approach here would be to first approximate the parent, + // but if the base type of the approximated parent is different from + // the current base type, then the current refinement won't be valid + // if it's a type parameter refinement. + // Therefore we first approximate the base type, then use `baseArgInfos` + // to get correct refinements for the approximated base type, then + // recursively approximate the resulting type. + val base = tp.unrefine + if (toAvoid(base)) { + val base1 = apply(base) + apply(base1.appliedTo(tp.baseArgInfos(base1.typeSymbol))) + } else { + val parent1 = apply(tp.parent) + val refinedInfo1 = apply(tp.refinedInfo) + if (toAvoid(refinedInfo1)) { + typr.println(s"dropping refinement from $tp") + parent1 + } else { + tp.derivedRefinedType(parent1, name, refinedInfo1) + } } - else tp1 case tp: TypeVar if ctx.typerState.constraint.contains(tp) => val lo = ctx.typerState.constraint.fullLowerBound(tp.origin) val lo1 = avoid(lo, symsToAvoid) -- cgit v1.2.3