From b2f888e1c9c3ac9b247375c264dd7aedb8156de5 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Tue, 20 Dec 2022 16:06:59 +0000 Subject: [PATCH] Delay widening in derivedSelect when avoiding Using the example from `pos/i16435.avoid`: class Foo: type Value def test: Option[Value] = val scr = { val self: Foo.this.type = this None: Option[self.Value] } scr We want avoidance to return `Option[Value]`, aka `Option[Foo.this.Value]`, rather than widening to `Option[Any]`. But also, widen when we're deriving to an intersection prefix... Test cases: i16105,i16435,i2945,i8900,i8861. And fix some kind of race condition in creating files/directories. --- compiler/src/dotty/tools/dotc/core/TypeOps.scala | 6 ++++-- compiler/src/dotty/tools/dotc/core/Types.scala | 2 +- compiler/src/dotty/tools/io/AbstractFile.scala | 6 ++++-- tests/pos/i16435.avoid.scala | 8 ++++++++ tests/pos/i16435.scala | 11 +++++++++++ 5 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 tests/pos/i16435.avoid.scala create mode 100644 tests/pos/i16435.scala diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index ffcdcbe9e869..cd25ea3fac2f 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -504,13 +504,15 @@ object TypeOps: override def derivedSelect(tp: NamedType, pre: Type) = if (pre eq tp.prefix) tp - else tryWiden(tp, tp.prefix).orElse { + else (if pre.isInstanceOf[AndType] then tryWiden(tp, tp.prefix) else NoType).orElse { if (tp.isTerm && variance > 0 && !pre.isSingleton) apply(tp.info.widenExpr) else if (upper(pre).member(tp.name).exists) super.derivedSelect(tp, pre) - else + else if (pre.isInstanceOf[AndType]) range(defn.NothingType, defn.AnyType) + else + tryWiden(tp, tp.prefix).orElse(range(defn.NothingType, defn.AnyType)) } end AvoidMap diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 666da728410b..2c0f53f5e801 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -5866,7 +5866,7 @@ object Types { * underlying bounds to a range, otherwise return the expansion. */ def expandParam(tp: NamedType, pre: Type): Type = - tp.argForParam(pre) match { + tp.argForParam(pre, widenAbstract = true) match { case arg @ TypeRef(pre, _) if pre.isArgPrefixOf(arg.symbol) => arg.info match { case argInfo: TypeBounds => expandBounds(argInfo) diff --git a/compiler/src/dotty/tools/io/AbstractFile.scala b/compiler/src/dotty/tools/io/AbstractFile.scala index 29bc764dcd7b..f34fe6f40b9c 100644 --- a/compiler/src/dotty/tools/io/AbstractFile.scala +++ b/compiler/src/dotty/tools/io/AbstractFile.scala @@ -260,8 +260,10 @@ abstract class AbstractFile extends Iterable[AbstractFile] { // a race condition in creating the entry after the failed lookup may throw val path = jpath.resolve(name) - if (isDir) Files.createDirectory(path) - else Files.createFile(path) + try + if (isDir) Files.createDirectory(path) + else Files.createFile(path) + catch case _: FileAlreadyExistsException => () new PlainFile(new File(path)) case lookup => lookup } diff --git a/tests/pos/i16435.avoid.scala b/tests/pos/i16435.avoid.scala new file mode 100644 index 000000000000..6fca050bd40b --- /dev/null +++ b/tests/pos/i16435.avoid.scala @@ -0,0 +1,8 @@ +class Foo: + type Value + def test: Option[Value] = + val scr = { + val self: Foo.this.type = this + None: Option[self.Value] + } + scr diff --git a/tests/pos/i16435.scala b/tests/pos/i16435.scala new file mode 100644 index 000000000000..3fb36efc55c9 --- /dev/null +++ b/tests/pos/i16435.scala @@ -0,0 +1,11 @@ +// scalac: -Werror +trait Base: + type Value + inline def oov: Option[Option[Value]] = None + def get: Option[Value] + +trait X extends Base: + override def get: Option[Value] = + oov match // was: match may not be exhaustive + case Some(ov) => ov + case None => None