From acd07c175c68dd84b690df0f53a3999c5f9e1afe Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 19 Mar 2016 19:46:47 +0100 Subject: [PATCH] Simplify and fix avoid logic The previous formulation broke for named parameters. Test case in flowops1.scala. --- src/dotty/tools/dotc/core/Types.scala | 8 ----- src/dotty/tools/dotc/typer/TypeAssigner.scala | 29 ++++++---------- tests/pos/flowops1.scala | 33 +++++++++++++++++++ 3 files changed, 43 insertions(+), 27 deletions(-) create mode 100644 tests/pos/flowops1.scala diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 3801f191449e..ffb662490320 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -841,14 +841,6 @@ object Types { case _ => this } - /** If this is a refinement type, the unrefined parent, - * else the type itself. - */ - final def unrefine(implicit ctx: Context): Type = stripTypeVar match { - case tp @ RefinedType(tycon, _) => tycon.unrefine - case _ => this - } - /** If this is a (possibly aliased, annotated, and/or parameterized) reference to * a class, the class type ref, otherwise NoType. * @param refinementOK If `true` we also skip non-parameter refinements. diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala index 84951fd2b3e9..840346536612 100644 --- a/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -6,6 +6,7 @@ import core._ import ast._ import Scopes._, Contexts._, Constants._, Types._, Symbols._, Names._, Flags._, Decorators._ import ErrorReporting._, Annotations._, Denotations._, SymDenotations._, StdNames._, TypeErasure._ +import TypeApplications.AppliedType import util.Positions._ import config.Printers._ import ast.Trees._ @@ -93,27 +94,17 @@ trait TypeAssigner { case _ => mapOver(tp) } + case tp @ AppliedType(tycon, args) if toAvoid(tycon) => + val base = apply(tycon) + apply(base.appliedTo(tp.baseArgInfos(base.typeSymbol))) 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))) + val parent1 = apply(tp.parent) + val refinedInfo1 = apply(tp.refinedInfo) + if (toAvoid(refinedInfo1)) { + typr.println(s"dropping refinement from $tp") + parent1 } 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) - } + tp.derivedRefinedType(parent1, name, refinedInfo1) } case tp: TypeVar if ctx.typerState.constraint.contains(tp) => val lo = ctx.typerState.constraint.fullLowerBound(tp.origin) diff --git a/tests/pos/flowops1.scala b/tests/pos/flowops1.scala new file mode 100644 index 000000000000..2acd515afa70 --- /dev/null +++ b/tests/pos/flowops1.scala @@ -0,0 +1,33 @@ +object Test { + class NotUsed + + trait FO[type +Out, type +Mat] { self => + type Repr <: FO[Mat = self.Mat] { + type Repr = self.Repr + } + def map[T](f: Out => T): Repr[Out = T] = ??? + } + + class Source[type +Out, type +Mat] extends FO[Out, Mat] { + type Repr <: Source[Out, Mat] + } + + class Flow[type -In, type +Out, type +Mat] extends FO[Out, Mat] { + type Repr <: Flow[In, Out, Mat] + } + + implicit class x[O, M, F <: FO](val f: F[Out = O, Mat = M]) extends AnyVal { + def xx(i: Int): f.Repr[Out = O] = f.map(identity) + } + + val s1 = new Source[Int, NotUsed].xx(12) + val s2: Source[Int, NotUsed] = s1 + val f1 = x[Int, NotUsed, Flow[In = Int]](new Flow[Int, Int, NotUsed]).xx(12) + val f2: Flow[Int, Int, NotUsed] = f1 + + + val f3 = x(new Flow[Int, Int, NotUsed]).xx(12) + val f4: Flow[Int, Int, NotUsed] = f3 + val f5 = new Flow[Int, Int, NotUsed].xx(12) + val f6: Flow[Int, Int, NotUsed] = f5 +}