diff options
author | odersky <odersky@gmail.com> | 2014-11-26 13:44:09 +0100 |
---|---|---|
committer | odersky <odersky@gmail.com> | 2014-11-26 13:44:09 +0100 |
commit | b18ce863f5f2444a5a00ccc9d55c4ee12115c467 (patch) | |
tree | f2f8a76eb5e8dd8926a35271118cf0e3b91182f5 /src/dotty/tools | |
parent | 5733684a4ec6857ece1048d56654dcd749163510 (diff) | |
parent | fc319b002ff4bc82061250352f1568c612c70d72 (diff) | |
download | dotty-b18ce863f5f2444a5a00ccc9d55c4ee12115c467.tar.gz dotty-b18ce863f5f2444a5a00ccc9d55c4ee12115c467.tar.bz2 dotty-b18ce863f5f2444a5a00ccc9d55c4ee12115c467.zip |
Merge pull request #244 from dotty-staging/fix/refinementTypes-v2
Allow refinements that refine already refined types.
Diffstat (limited to 'src/dotty/tools')
-rw-r--r-- | src/dotty/tools/dotc/ast/Desugar.scala | 42 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 2 |
2 files changed, 36 insertions, 8 deletions
diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala index 1aab16469..05f652a39 100644 --- a/src/dotty/tools/dotc/ast/Desugar.scala +++ b/src/dotty/tools/dotc/ast/Desugar.scala @@ -834,17 +834,45 @@ object desugar { } }.withPos(tree.pos) - /** Create a class definition with the same info as this refined type. + /** Create a class definition with the same info as the refined type given by `parent` + * and `refinements`. + * * parent { refinements } * ==> - * trait <refinement> extends parent { refinements } + * trait <refinement> extends core { this: self => refinements } + * + * Here, `core` is the (possibly parameterized) class part of `parent`. + * If `parent` is the same as `core`, self is empty. Otherwise `self` is `parent`. + * + * Example: Given + * + * class C + * type T1 extends C { type T <: A } + * + * the refined type * - * If the parent is missing, Object is assumed. - * The result is used for validity checking, is thrown away afterwards. + * T1 { type T <: B } + * + * is expanded to + * + * trait <refinement> extends C { this: T1 => type T <: A } + * + * The result of this method is used for validity checking, is thrown away afterwards. + * @param parentType The type of `parent` */ - def refinedTypeToClass(tree: RefinedTypeTree)(implicit ctx: Context): TypeDef = { - val parent = if (tree.tpt.isEmpty) TypeTree(defn.ObjectType) else tree.tpt - val impl = Template(emptyConstructor, parent :: Nil, EmptyValDef, tree.refinements) + 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 + case tp: TypeProxy => stripToCore(tp.underlying) + case _ => defn.AnyType + } + val parentCore = 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) 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 9ef73f0b6..7d4e8d132 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -756,7 +756,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def typedRefinedTypeTree(tree: untpd.RefinedTypeTree)(implicit ctx: Context): RefinedTypeTree = track("typedRefinedTypeTree") { val tpt1 = if (tree.tpt.isEmpty) TypeTree(defn.ObjectType) else typedAheadType(tree.tpt) - val refineClsDef = desugar.refinedTypeToClass(tree) + val refineClsDef = desugar.refinedTypeToClass(tpt1, tree.refinements) val refineCls = createSymbol(refineClsDef).asClass val TypeDef(_, Template(_, _, _, refinements1)) = typed(refineClsDef) assert(tree.refinements.length == refinements1.length, s"${tree.refinements} != $refinements1") |