diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala index 7cdedb19a6cb..cd198818aba4 100644 --- a/src/dotty/tools/dotc/ast/Desugar.scala +++ b/src/dotty/tools/dotc/ast/Desugar.scala @@ -864,18 +864,19 @@ object desugar { * @param parentType The type of `parent` */ def refinedTypeToClass(parent: tpd.Tree, refinements: List[Tree])(implicit ctx: Context): TypeDef = { - def stripToCore(tp: Type): Type = tp match { - case tp: RefinedType if tp.argInfos.nonEmpty => tp // parameterized class type - case tp: TypeRef if tp.symbol.isClass => tp // monomorphic class type + def stripToCore(tp: Type): List[Type] = tp match { + case tp: RefinedType if tp.argInfos.nonEmpty => tp :: Nil // parameterized class type + case tp: TypeRef if tp.symbol.isClass => tp :: Nil // monomorphic class type case tp: TypeProxy => stripToCore(tp.underlying) - case _ => defn.AnyType + case AndType(tp1, tp2) => stripToCore(tp1) ::: stripToCore(tp2) + case _ => defn.AnyType :: Nil } - val parentCore = stripToCore(parent.tpe) + val parentCores = stripToCore(parent.tpe) val untpdParent = TypedSplice(parent) - val (classParent, self) = - if (parent.tpe eq parentCore) (untpdParent, EmptyValDef) - else (TypeTree(parentCore), ValDef(nme.WILDCARD, untpdParent, EmptyTree)) - val impl = Template(emptyConstructor, classParent :: Nil, self, refinements) + val (classParents, self) = + if (parentCores.length == 1 && (parent.tpe eq parentCores.head)) (untpdParent :: Nil, EmptyValDef) + else (parentCores map TypeTree, ValDef(nme.WILDCARD, untpdParent, EmptyTree)) + val impl = Template(emptyConstructor, classParents, self, refinements) TypeDef(tpnme.REFINE_CLASS, impl).withFlags(Trait) } diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 1e07cbf793b1..7d1e950f4cf5 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -793,6 +793,10 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit typr.println(s"adding refinement $refinement") checkRefinementNonCyclic(refinement, refineCls, seen) val rsym = refinement.symbol + if ((rsym.is(Method) || rsym.isType) && rsym.allOverriddenSymbols.isEmpty) { + println(refineCls.baseClasses) + ctx.error(i"refinement $rsym without matching type in parent $parent", refinement.pos) + } val rinfo = if (rsym is Accessor) rsym.info.resultType else rsym.info RefinedType(parent, rsym.name, rt => rinfo.substThis(refineCls, SkolemType(rt))) // todo later: check that refinement is within bounds diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index a9ce5a18a47a..f4f11a519f88 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -59,7 +59,6 @@ class tests extends CompilerTest { @Test def pos_overrides() = compileFile(posDir, "overrides") @Test def pos_javaOverride() = compileDir(posDir + "java-override") @Test def pos_templateParents() = compileFile(posDir, "templateParents") - @Test def pos_structural() = compileFile(posDir, "structural") @Test def pos_overloadedAccess = compileFile(posDir, "overloadedAccess") @Test def pos_approximateUnion = compileFile(posDir, "approximateUnion") @Test def pos_tailcall = compileDir(posDir + "tailcall/") @@ -87,16 +86,10 @@ class tests extends CompilerTest { @Test def neg_over = compileFile(negDir, "over", xerrors = 3) @Test def neg_overrides = compileFile(negDir, "overrides", xerrors = 11) @Test def neg_projections = compileFile(negDir, "projections", xerrors = 1) - @Test def neg_i39 = compileFile(negDir, "i39", xerrors = 1) - @Test def neg_i50_volatile = compileFile(negDir, "i50-volatile", xerrors = 4) + @Test def neg_i39 = compileFile(negDir, "i39", xerrors = 2) + @Test def neg_i50_volatile = compileFile(negDir, "i50-volatile", xerrors = 6) @Test def neg_t0273_doubledefs = compileFile(negDir, "t0273", xerrors = 1) - @Test def neg_t0586_structural = compileFile(negDir, "t0586", xerrors = 1) - @Test def neg_t0625_structural = compileFile(negDir, "t0625", xerrors = 1)( - defaultOptions = noCheckOptions) - // -Ycheck fails because there are structural types involving higher-kinded types. - // these are illegal, but are tested only later. - @Test def neg_t1131_structural = compileFile(negDir, "t1131", xerrors = 1) - @Test def neg_zoo = compileFile(negDir, "zoo", xerrors = 1) + @Test def neg_zoo = compileFile(negDir, "zoo", xerrors = 12) @Test def neg_t1192_legalPrefix = compileFile(negDir, "t1192", xerrors = 1) @Test def neg_tailcall_t1672b = compileFile(negDir, "tailcall/t1672b", xerrors = 6) @Test def neg_tailcall_t3275 = compileFile(negDir, "tailcall/t3275", xerrors = 1) @@ -108,13 +101,13 @@ class tests extends CompilerTest { @Test def neg_t1843_variances = compileFile(negDir, "t1843-variances", xerrors = 1) @Test def neg_t2660_ambi = compileFile(negDir, "t2660", xerrors = 2) @Test def neg_t2994 = compileFile(negDir, "t2994", xerrors = 2) - @Test def neg_subtyping = compileFile(negDir, "subtyping", xerrors = 2) + @Test def neg_subtyping = compileFile(negDir, "subtyping", xerrors = 4) @Test def neg_variances = compileFile(negDir, "variances", xerrors = 2) @Test def neg_badAuxConstr = compileFile(negDir, "badAuxConstr", xerrors = 2) @Test def neg_typetest = compileFile(negDir, "typetest", xerrors = 1) @Test def neg_t1569_failedAvoid = compileFile(negDir, "t1569-failedAvoid", xerrors = 1) @Test def neg_cycles = compileFile(negDir, "cycles", xerrors = 8) - @Test def neg_boundspropagation = compileFile(negDir, "boundspropagation", xerrors = 4) + @Test def neg_boundspropagation = compileFile(negDir, "boundspropagation", xerrors = 5) @Test def neg_refinedSubtyping = compileFile(negDir, "refinedSubtyping", xerrors = 2) @Test def neg_i0091_infpaths = compileFile(negDir, "i0091-infpaths", xerrors = 3) @Test def neg_i0248_inherit_refined = compileFile(negDir, "i0248-inherit-refined", xerrors = 4) diff --git a/tests/neg/structural.scala b/tests/neg/structural.scala new file mode 100644 index 000000000000..1d25062909f3 --- /dev/null +++ b/tests/neg/structural.scala @@ -0,0 +1,70 @@ +package p1 { + +object test123 { + type A = { def a: Int } + def f(a: A): A = a +} + +object structural2 { + type A = { def a: Int } + + type B = { + def b: Int + } + + type AB = A & B + + def f(ab: AB): AB = ab + + f(new { + def a = 43 + def b = 42 + }) +} +} + +package p2 { +object RClose { + type ReflectCloseable = { def close(): Unit } + def withReflectCloseable[T <: ReflectCloseable, R](s: T)(action: T => R): R = + try { + action(s) + } finally { + s.close() + } +} +} + +package p3 { +object Test { + def idMap[C[_],T](m: { def map[U](f: T => U): C[U] }): C[T] = m.map(t => t) + + def main(args: Array[String]): Unit = { + idMap(Some(5)) + idMap(Responder.constant(5)) + } +} +} +package p4 { + +trait A { self: Any { def p: Any } => + def f(b: => Unit): Unit = {} + f { p } // error: cannot access member 'p' from structural type +} +} + +package p5 { +// t2810 +object Test { + val closeable1: { def close(): Unit } = new scala.io.Source { val iter: Iterator[Char] = "".iterator } + val closeable2: { def close(): Unit } = new java.io.Closeable { def close() = {} } +} +} + +package p6 { + + class Refinements { + val y: C { val x: T; type T } // was adeprecated warning: illegal forward reference in refinement; now illegal + } + +} diff --git a/tests/neg/t0586.scala b/tests/neg/t0586.scala deleted file mode 100644 index 540e225a1465..000000000000 --- a/tests/neg/t0586.scala +++ /dev/null @@ -1,9 +0,0 @@ -object RClose { - type ReflectCloseable = { def close(): Unit } - def withReflectCloseable[T <: ReflectCloseable, R](s: T)(action: T => R): R = - try { - action(s) - } finally { - s.close() - } -} diff --git a/tests/neg/t0625.scala b/tests/neg/t0625.scala deleted file mode 100644 index 56145425998f..000000000000 --- a/tests/neg/t0625.scala +++ /dev/null @@ -1,8 +0,0 @@ -object Test { - def idMap[C[_],T](m: { def map[U](f: T => U): C[U] }): C[T] = m.map(t => t) - - def main(args: Array[String]): Unit = { - idMap(Some(5)) - idMap(Responder.constant(5)) - } -} diff --git a/tests/neg/t1131.scala b/tests/neg/t1131.scala deleted file mode 100644 index f4a7b377d98a..000000000000 --- a/tests/neg/t1131.scala +++ /dev/null @@ -1,4 +0,0 @@ -trait A { self: Any { def p: Any } => - def f(b: => Unit): Unit = {} - f { p } // error: cannot access member 'p' from structural type -} diff --git a/tests/neg/typers.scala b/tests/neg/typers.scala index 226fd2310408..b5bd1fa2c129 100644 --- a/tests/neg/typers.scala +++ b/tests/neg/typers.scala @@ -60,8 +60,4 @@ object typers { 123 } } - - class Refinements { - val y: C { val x: T; type T } // deprecated warning: illegal forward reference in refinement - } } diff --git a/tests/pos/i262-null-subtyping.scala b/tests/pos/i262-null-subtyping.scala index 284be49e8520..5e57fcca0a8f 100644 --- a/tests/pos/i262-null-subtyping.scala +++ b/tests/pos/i262-null-subtyping.scala @@ -1,12 +1,9 @@ object O { - // This compiles - val a: { type T } = null; - val b: Any { type T } = null; + trait Base extends Any { type T } + val a: Base { type T } = null; + val b: Any with Base { type T } = null; - // This doesn't: - // found : Null - // required: AnyRef{T} - val c: AnyRef { type T } = null; + val c: AnyRef with Base { type T } = null; class A class B diff --git a/tests/pos/structural.scala b/tests/pos/structural.scala deleted file mode 100644 index 8afa49ed0e0b..000000000000 --- a/tests/pos/structural.scala +++ /dev/null @@ -1,21 +0,0 @@ -object test123 { - type A = { def a: Int } - def f(a: A): A = a -} - -object structural2 { - type A = { def a: Int } - - type B = { - def b: Int - } - - type AB = A & B - - def f(ab: AB): AB = ab - - f(new { - def a = 43 - def b = 42 - }) -} \ No newline at end of file diff --git a/tests/pos/t1053.scala b/tests/pos/t1053.scala index 1d4dfb637e99..2c5dc1d5a9d8 100644 --- a/tests/pos/t1053.scala +++ b/tests/pos/t1053.scala @@ -1,6 +1,7 @@ trait T[A] { trait U { type W = A; val x = 3 } } +trait Base { type V } object Test { - val x : ({ type V = T[this.type] })#V = null + val x : (Base { type V = T[this.type] })#V = null val y = new x.U { } } diff --git a/tests/pos/t2810.scala b/tests/pos/t2810.scala deleted file mode 100644 index c85eca164aa3..000000000000 --- a/tests/pos/t2810.scala +++ /dev/null @@ -1,8 +0,0 @@ - - - - -object Test { - val closeable1: { def close(): Unit } = new scala.io.Source { val iter: Iterator[Char] = "".iterator } - val closeable2: { def close(): Unit } = new java.io.Closeable { def close() = {} } -} diff --git a/tests/pos/typers.scala b/tests/pos/typers.scala index fe11ca6021be..7f67d2c7265a 100644 --- a/tests/pos/typers.scala +++ b/tests/pos/typers.scala @@ -88,6 +88,7 @@ object typers { } class Refinements { + trait C { type T; def process(x: T): Int } val y: C { type T; val key: T; def process(x: T): Int } = ??? } diff --git a/tests/pos/zoo.scala b/tests/pos/zoo.scala index 08f7eba6380f..02dac8f5bf32 100644 --- a/tests/pos/zoo.scala +++ b/tests/pos/zoo.scala @@ -1,40 +1,37 @@ object Test { -type Meat = { +trait FoodStuff +trait Meat extends FoodStuff { type IsMeat = Any } -type Grass = { +trait Grass extends FoodStuff { type IsGrass = Any } -type Animal = { - type Food +trait Animal { + type Food <: FoodStuff def eats(food: Food): Unit def gets: Food } -type Cow = { +trait Cow extends Animal { type IsMeat = Any type Food <: Grass def eats(food: Grass): Unit - def gets: Grass + def gets: Food } -type Lion = { +trait Lion extends Animal { type Food = Meat def eats(food: Meat): Unit def gets: Meat } -def newMeat: Meat = new { - type IsMeat = Any +def newMeat: Meat = new Meat { } -def newGrass: Grass = new { - type IsGrass = Any +def newGrass: Grass = new Grass { } -def newCow: Cow = new { - type IsMeat = Any +def newCow: Cow = new Cow { type Food = Grass def eats(food: Grass) = () def gets = newGrass } -def newLion: Lion = new { - type Food = Meat +def newLion: Lion = new Lion { def eats(food: Meat) = () def gets = newMeat }