From 7103791b24066a5abb3e55507afbd06cfdee519c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 29 Apr 2021 13:18:07 +0200 Subject: [PATCH] Don't strip @uncheckedVariance when inferring the type of default getters Fixes #12273 --- compiler/src/dotty/tools/dotc/core/TypeOps.scala | 4 +++- compiler/src/dotty/tools/dotc/typer/Namer.scala | 10 ++++++---- tests/pos/i12273.scala | 4 ++++ 3 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 tests/pos/i12273.scala diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index eb353744ae82..09ac61d304b8 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -164,7 +164,7 @@ object TypeOps: // corrective steps, so no widening is wanted. simplify(l, theMap) | simplify(r, theMap) case AnnotatedType(parent, annot) - if !ctx.mode.is(Mode.Type) && annot.symbol == defn.UncheckedVarianceAnnot => + if annot.symbol == defn.UncheckedVarianceAnnot && !ctx.mode.is(Mode.Type) && !theMap.isInstanceOf[SimplifyKeepUnchecked] => simplify(parent, theMap) case _: MatchType => val normed = tp.tryNormalize @@ -180,6 +180,8 @@ object TypeOps: def apply(tp: Type): Type = simplify(tp, this) } + class SimplifyKeepUnchecked(using Context) extends SimplifyMap + /** Approximate union type by intersection of its dominators. * That is, replace a union type Tn | ... | Tn * by the smallest intersection type of base-class instances of T1,...,Tn. diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 10872e39b516..141e9f67b5f9 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -1550,10 +1550,12 @@ class Namer { typer: Typer => // For justification on the use of `@uncheckedVariance`, see // `default-getter-variance.scala`. AnnotatedType(defaultTp, Annotation(defn.UncheckedVarianceAnnot)) - else tp.widenTermRefExpr.simplified match - case ctp: ConstantType if isInlineVal => ctp - case tp => - TypeComparer.widenInferred(tp, pt) + else + // don't strip @uncheckedVariance annot for default getters + TypeOps.simplify(tp.widenTermRefExpr, + if defaultTp.exists then TypeOps.SimplifyKeepUnchecked() else null) match + case ctp: ConstantType if isInlineVal => ctp + case tp => TypeComparer.widenInferred(tp, pt) // Replace aliases to Unit by Unit itself. If we leave the alias in // it would be erased to BoxedUnit. diff --git a/tests/pos/i12273.scala b/tests/pos/i12273.scala new file mode 100644 index 000000000000..1201c2fc62bd --- /dev/null +++ b/tests/pos/i12273.scala @@ -0,0 +1,4 @@ +import scala.annotation.unchecked.uncheckedVariance + +final case class Outlet[T](out: T) +final case class SourceShape[+T](val out: Outlet[T @uncheckedVariance]) \ No newline at end of file