From b7be8ec3dc4219e3291b653c5ab9d5934f5fdb7e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 14 Mar 2017 16:47:55 +0100 Subject: [PATCH 1/5] Encode variances in parameter names This leads to a slight overall simplification, harmonizes pickle format with internal representation, and makes MethodTypes and PolyTypes more similar to each other. I believe the change is useful as it is, but in particular it is a useful step for an eventual unification of MethodTypes and PolyTypes. --- .../src/dotty/tools/dotc/ast/Desugar.scala | 6 ++++ .../dotty/tools/dotc/core/Definitions.scala | 2 +- .../src/dotty/tools/dotc/core/NameOps.scala | 26 +++++++++++++- .../src/dotty/tools/dotc/core/StdNames.scala | 1 - .../tools/dotc/core/TypeApplications.scala | 9 +++-- .../dotty/tools/dotc/core/TypeComparer.scala | 8 ++--- .../src/dotty/tools/dotc/core/Types.scala | 35 ++++++++++++------- .../tools/dotc/core/tasty/TastyFormat.scala | 6 +--- .../tools/dotc/core/tasty/TreePickler.scala | 4 +-- .../tools/dotc/core/tasty/TreeUnpickler.scala | 6 ++-- .../tools/dotc/printing/PlainPrinter.scala | 8 ++--- .../dotc/transform/FullParameterization.scala | 4 +-- .../dotty/tools/dotc/typer/ProtoTypes.scala | 2 +- 13 files changed, 76 insertions(+), 41 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index b5be894402fa..8afc89bdbe93 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -241,6 +241,12 @@ object desugar { * class C { type v C$T; type v T = C$T } */ def typeDef(tdef: TypeDef)(implicit ctx: Context): Tree = { + val name = + if (tdef.name.hasVariance && tdef.mods.is(Param)) { + ctx.error(em"type parameter name may not start with `+' or `-'", tdef.pos) + ("$" + tdef.name).toTypeName + } + else tdef.name if (tdef.mods is PrivateLocalParam) { val tparam = cpy.TypeDef(tdef)(name = tdef.name.expandedName(ctx.owner)) .withMods(tdef.mods &~ PrivateLocal | ExpandedName) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 4d4350f98651..3f99fa71bbe5 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -152,7 +152,7 @@ class Definitions { resultTypeFn: PolyType => Type, flags: FlagSet = EmptyFlags) = { val tparamNames = tpnme.syntheticTypeParamNames(typeParamCount) val tparamBounds = tparamNames map (_ => TypeBounds.empty) - val ptype = PolyType(tparamNames, tparamNames.map(alwaysZero))(_ => tparamBounds, resultTypeFn) + val ptype = PolyType(tparamNames)(_ => tparamBounds, resultTypeFn) enterMethod(cls, name, ptype, flags) } diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index ea905c19f50a..240ad359bba1 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -196,6 +196,31 @@ object NameOps { if (name.isModuleClassName) name.stripModuleClassSuffix.freshened.moduleClassName else likeTyped(ctx.freshName(name ++ NameTransformer.NAME_JOIN_STRING))) + /** Name with variance prefix: `+` for covariant, `-` for contravariant */ + def withVariance(v: Int): N = + if (hasVariance) dropVariance.withVariance(v) + else v match { + case -1 => likeTyped('-' +: name) + case 1 => likeTyped('+' +: name) + case 0 => name + } + + /** Does name have a `+`/`-` variance prefix? */ + def hasVariance: Boolean = + name.nonEmpty && name.head == '+' || name.head == '-' + + /** Drop variance prefix if name has one */ + def dropVariance: N = if (hasVariance) likeTyped(name.tail) else name + + /** The variance as implied by the variance prefix, or 0 if there is + * no variance prefix. + */ + def variance = name.head match { + case '-' => -1 + case '+' => 1 + case _ => 0 + } + /** Translate a name into a list of simple TypeNames and TermNames. * In all segments before the last, type/term is determined by whether * the following separator char is '.' or '#'. The last segment @@ -271,7 +296,6 @@ object NameOps { else -1 } - /** The number of hops specified in an outer-select name */ def outerSelectHops: Int = { require(isOuterSelect) diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 5b7dc3d1d5b2..2bb26f327988 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -846,5 +846,4 @@ object StdNames { val tpnme = new ScalaTypeNames val jnme = new JavaTermNames val jtpnme = new JavaTypeNames - } diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index c713cd54274f..a9487c30dd64 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -277,9 +277,10 @@ class TypeApplications(val self: Type) extends AnyVal { * TODO: Handle parameterized lower bounds */ def LambdaAbstract(tparams: List[TypeParamInfo])(implicit ctx: Context): Type = { + def nameWithVariance(tparam: TypeParamInfo) = + tparam.paramName.withVariance(tparam.paramVariance) def expand(tp: Type) = - PolyType( - tparams.map(_.paramName), tparams.map(_.paramVariance))( + PolyType(tparams.map(nameWithVariance))( tl => tparams.map(tparam => tl.lifted(tparams, tparam.paramBounds).bounds), tl => tl.lifted(tparams, tp)) if (tparams.isEmpty) self @@ -364,7 +365,9 @@ class TypeApplications(val self: Type) extends AnyVal { case arg @ PolyType(tparams, body) if !tparams.corresponds(hkParams)(_.paramVariance == _.paramVariance) && tparams.corresponds(hkParams)(varianceConforms) => - PolyType(tparams.map(_.paramName), hkParams.map(_.paramVariance))( + PolyType( + (tparams, hkParams).zipped.map((tparam, hkparam) => + tparam.paramName.withVariance(hkparam.paramVariance)))( tl => arg.paramBounds.map(_.subst(arg, tl).bounds), tl => arg.resultType.subst(arg, tl) ) diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 21a12dbb744b..a934b3ac6f82 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -669,7 +669,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { val tparams1 = tparams1a.drop(lengthDiff) variancesConform(tparams1, tparams) && { if (lengthDiff > 0) - tycon1b = PolyType(tparams1.map(_.paramName), tparams1.map(_.paramVariance))( + tycon1b = PolyType(tparams1.map(_.paramName))( tl => tparams1.map(tparam => tl.lifted(tparams, tparam.paramBounds).bounds), tl => tycon1a.appliedTo(args1.take(lengthDiff) ++ tparams1.indices.toList.map(PolyParam(tl, _)))) @@ -1279,9 +1279,9 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { original(tp1.appliedTo(tp1.typeParams.map(_.paramBoundsAsSeenFrom(tp1))), tp2) else PolyType( - paramNames = tpnme.syntheticTypeParamNames(tparams1.length), - variances = (tparams1, tparams2).zipped.map((tparam1, tparam2) => - (tparam1.paramVariance + tparam2.paramVariance) / 2))( + paramNames = (tpnme.syntheticTypeParamNames(tparams1.length), tparams1, tparams2) + .zipped.map((pname, tparam1, tparam2) => + pname.withVariance((tparam1.paramVariance + tparam2.paramVariance) / 2)))( paramBoundsExp = tl => (tparams1, tparams2).zipped.map((tparam1, tparam2) => tl.lifted(tparams1, tparam1.paramBoundsAsSeenFrom(tp1)).bounds & tl.lifted(tparams2, tparam2.paramBoundsAsSeenFrom(tp2)).bounds), diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 54251cbb1fd8..a05b147e352d 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2567,8 +2567,20 @@ object Types { } } - /** A type lambda of the form `[v_0 X_0, ..., v_n X_n] => T` */ - class PolyType(val paramNames: List[TypeName], val variances: List[Int])( + /** A type lambda of the form `[X_0 B_0, ..., X_n B_n] => T` + * This is used both as a type of a polymorphic method and as a type of + * a higher-kidned type parameter. Variances are encoded in parameter + * names. A name starting with `+` designates a covariant parameter, + * a name starting with `-` designates a contravariant parameter, + * and every other name designates a non-variant parameter. + * + * @param paramNames The names `X_0`, ..., `X_n` + * @param paramBoundsExp A function that, given the polytype itself, returns the + * parameter bounds `B_1`, ..., `B_n` + * @param resultTypeExp A function that, given the polytype itself, returns the + * result type `T`. + */ + class PolyType(val paramNames: List[TypeName])( paramBoundsExp: PolyType => List[TypeBounds], resultTypeExp: PolyType => Type) extends CachedProxyType with BindingType with MethodOrPoly { @@ -2606,7 +2618,7 @@ object Types { paramBounds.mapConserve(_.substParams(this, argTypes).bounds) def newLikeThis(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context): PolyType = - PolyType.apply(paramNames, variances)( + PolyType.apply(paramNames)( x => paramBounds mapConserve (_.subst(this, x).bounds), x => resType.subst(this, x)) @@ -2639,7 +2651,7 @@ object Types { case t => mapOver(t) } } - PolyType(paramNames ++ that.paramNames, variances ++ that.variances)( + PolyType(paramNames ++ that.paramNames)( x => this.paramBounds.mapConserve(_.subst(this, x).bounds) ++ that.paramBounds.mapConserve(shift(_).subst(that, x).bounds), x => shift(that.resultType).subst(that, x).subst(this, x)) @@ -2659,28 +2671,27 @@ object Types { case other: PolyType => other.paramNames == this.paramNames && other.paramBounds == this.paramBounds && - other.resType == this.resType && - other.variances == this.variances + other.resType == this.resType case _ => false } - override def toString = s"PolyType($variances, $paramNames, $paramBounds, $resType)" + override def toString = s"PolyType($paramNames, $paramBounds, $resType)" - override def computeHash = doHash(variances ::: paramNames, resType, paramBounds) + override def computeHash = doHash(paramNames, resType, paramBounds) } object PolyType { - def apply(paramNames: List[TypeName], variances: List[Int])( + def apply(paramNames: List[TypeName])( paramBoundsExp: PolyType => List[TypeBounds], resultTypeExp: PolyType => Type)(implicit ctx: Context): PolyType = { - unique(new PolyType(paramNames, variances)(paramBoundsExp, resultTypeExp)) + unique(new PolyType(paramNames)(paramBoundsExp, resultTypeExp)) } def unapply(tl: PolyType): Some[(List[LambdaParam], Type)] = Some((tl.typeParams, tl.resType)) def any(n: Int)(implicit ctx: Context) = - apply(tpnme.syntheticTypeParamNames(n), List.fill(n)(0))( + apply(tpnme.syntheticTypeParamNames(n))( pt => List.fill(n)(TypeBounds.empty), pt => defn.AnyType) } @@ -2693,7 +2704,7 @@ object Types { def paramBounds(implicit ctx: Context): TypeBounds = tl.paramBounds(n) def paramBoundsAsSeenFrom(pre: Type)(implicit ctx: Context): TypeBounds = paramBounds def paramBoundsOrCompleter(implicit ctx: Context): Type = paramBounds - def paramVariance(implicit ctx: Context): Int = tl.variances(n) + def paramVariance(implicit ctx: Context): Int = tl.paramNames(n).variance def toArg: Type = PolyParam(tl, n) def paramRef(implicit ctx: Context): Type = PolyParam(tl, n) } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index cb1b56c3c3d5..98577f3c5070 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -151,7 +151,7 @@ Standard-Section: "ASTs" TopLevelStat* BIND Length boundName_NameRef bounds_Type // for type-variables defined in a type pattern BYNAMEtype underlying_Type - POLYtype Length result_Type NamesTypes // variance encoded in front of name: +/-/= + POLYtype Length result_Type NamesTypes // variance encoded in front of name: +/-/(nothing) METHODtype Length result_Type NamesTypes // needed for refinements PARAMtype Length binder_ASTref paramNum_Nat // needed for refinements SHARED type_ASTRef @@ -546,8 +546,4 @@ object TastyFormat { case POLYtype | METHODtype => -1 case _ => 0 } - - /** Map between variances and name prefixes */ - val varianceToPrefix = Map(-1 -> '-', 0 -> '=', 1 -> '+') - val prefixToVariance = Map('-' -> -1, '=' -> 0, '+' -> 1) } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 80270aa25e0e..871f398388d5 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -255,9 +255,7 @@ class TreePickler(pickler: TastyPickler) { pickleType(tpe.underlying) case tpe: PolyType => writeByte(POLYtype) - val paramNames = tpe.typeParams.map(tparam => - varianceToPrefix(tparam.paramVariance) +: tparam.paramName) - pickleMethodic(tpe.resultType, paramNames, tpe.paramBounds) + pickleMethodic(tpe.resultType, tpe.paramNames, tpe.paramBounds) case tpe: MethodType if richTypes => writeByte(METHODtype) pickleMethodic(tpe.resultType, tpe.paramNames, tpe.paramTypes) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index a9ea49ad1fde..8ed5bd3c3ad4 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -268,10 +268,8 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle registerSym(start, sym) TypeRef.withFixedSym(NoPrefix, sym.name, sym) case POLYtype => - val (rawNames, paramReader) = readNamesSkipParams - val (variances, paramNames) = rawNames - .map(name => (prefixToVariance(name.head), name.tail.toTypeName)).unzip - val result = PolyType(paramNames, variances)( + val (paramNames, paramReader) = readNamesSkipParams + val result = PolyType(paramNames.map(_.toTypeName))( pt => registeringType(pt, paramReader.readParamTypes[TypeBounds](end)), pt => readType()) goto(end) diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index 67d44daa1ee7..ba5592bd6a89 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -176,10 +176,9 @@ class PlainPrinter(_ctx: Context) extends Printer { case tp: ExprType => changePrec(GlobalPrec) { "=> " ~ toText(tp.resultType) } case tp: PolyType => - def paramText(variance: Int, name: Name, bounds: TypeBounds): Text = - varianceString(variance) ~ name.toString ~ toText(bounds) + def paramText(name: Name, bounds: TypeBounds): Text = name.toString ~ toText(bounds) changePrec(GlobalPrec) { - "[" ~ Text((tp.variances, tp.paramNames, tp.paramBounds).zipped.map(paramText), ", ") ~ + "[" ~ Text((tp.paramNames, tp.paramBounds).zipped.map(paramText), ", ") ~ "]" ~ (" => " provided !tp.resultType.isInstanceOf[MethodType]) ~ toTextGlobal(tp.resultType) } @@ -209,7 +208,8 @@ class PlainPrinter(_ctx: Context) extends Printer { protected def polyParamNameString(name: TypeName): String = name.toString - protected def polyParamNameString(param: PolyParam): String = polyParamNameString(param.binder.paramNames(param.paramNum)) + protected def polyParamNameString(param: PolyParam): String = + polyParamNameString(param.binder.paramNames(param.paramNum)) /** The name of the symbol without a unique id. Under refined printing, * the decoded original name. diff --git a/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala b/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala index 0cb453b4c197..cdc28b23f2d5 100644 --- a/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala +++ b/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala @@ -122,14 +122,14 @@ trait FullParameterization { info match { case info: PolyType => - PolyType(info.paramNames ++ ctnames, info.variances ++ ctvariances)( + PolyType(info.paramNames ++ ctnames)( pt => (info.paramBounds.map(mapClassParams(_, pt).bounds) ++ mappedClassBounds(pt)).mapConserve(_.subst(info, pt).bounds), pt => resultType(mapClassParams(_, pt)).subst(info, pt)) case _ => if (ctparams.isEmpty) resultType(identity) - else PolyType(ctnames, ctvariances)(mappedClassBounds, pt => resultType(mapClassParams(_, pt))) + else PolyType(ctnames)(mappedClassBounds, pt => resultType(mapClassParams(_, pt))) } } diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index f7dd725c8672..236088c3ff6e 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -401,7 +401,7 @@ object ProtoTypes { /** Create a new polyparam that represents a dependent method parameter singleton */ def newDepPolyParam(tp: Type)(implicit ctx: Context): PolyParam = { - val poly = PolyType(ctx.freshName(nme.DEP_PARAM_PREFIX).toTypeName :: Nil, 0 :: Nil)( + val poly = PolyType(ctx.freshName(nme.DEP_PARAM_PREFIX).toTypeName :: Nil)( pt => TypeBounds.upper(AndType(tp, defn.SingletonType)) :: Nil, pt => defn.AnyType) ctx.typeComparer.addToConstraint(poly, Nil) From a1877fb1bc84b648f36c362d82838867716bdda3 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 14 Mar 2017 17:26:58 +0100 Subject: [PATCH 2/5] Add neg test for illegal parameter names and fix typo --- compiler/src/dotty/tools/dotc/core/Types.scala | 2 +- tests/neg/illegal-param-names.scala | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 tests/neg/illegal-param-names.scala diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index a05b147e352d..1249ba33511b 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2569,7 +2569,7 @@ object Types { /** A type lambda of the form `[X_0 B_0, ..., X_n B_n] => T` * This is used both as a type of a polymorphic method and as a type of - * a higher-kidned type parameter. Variances are encoded in parameter + * a higher-kinded type parameter. Variances are encoded in parameter * names. A name starting with `+` designates a covariant parameter, * a name starting with `-` designates a contravariant parameter, * and every other name designates a non-variant parameter. diff --git a/tests/neg/illegal-param-names.scala b/tests/neg/illegal-param-names.scala new file mode 100644 index 000000000000..9ca06798a0d6 --- /dev/null +++ b/tests/neg/illegal-param-names.scala @@ -0,0 +1 @@ +class Test[++, --] // error // error From 021cab18aec47f5a89388ba10224cbc2fd4bc016 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 14 Mar 2017 17:36:00 +0100 Subject: [PATCH 3/5] Fix dottydoc parameter printing --- doc-tool/src/dotty/tools/dottydoc/core/DocASTPhase.scala | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/doc-tool/src/dotty/tools/dottydoc/core/DocASTPhase.scala b/doc-tool/src/dotty/tools/dottydoc/core/DocASTPhase.scala index cfb66fa568d8..ad8981ea21df 100644 --- a/doc-tool/src/dotty/tools/dottydoc/core/DocASTPhase.scala +++ b/doc-tool/src/dotty/tools/dottydoc/core/DocASTPhase.scala @@ -94,10 +94,7 @@ class DocASTPhase extends Phase { NonEntity else { val tparams = t.rhs.tpe match { - case tp: PolyType => tp.paramRefs.zip(tp.variances).map { case (tp, variance) => - val varianceSym = if (variance == 1) "+" else if (variance == -1) "-" else "" - varianceSym + tp.paramName.show - } + case tp: PolyType => tp.paramNames.map(_.show) case _ => Nil } TypeAliasImpl(sym, annotations(sym), flags(t), t.name.show.split("\\$\\$").last, path(sym), alias(t.rhs.tpe), tparams) From 517d9c3cd6db49388d559daa00db2a0a5ed904ae Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 14 Mar 2017 17:49:32 +0100 Subject: [PATCH 4/5] Don't let illegal parameter names propagate into types --- compiler/src/dotty/tools/dotc/ast/Desugar.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 8afc89bdbe93..497b3791ed8e 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -241,20 +241,20 @@ object desugar { * class C { type v C$T; type v T = C$T } */ def typeDef(tdef: TypeDef)(implicit ctx: Context): Tree = { - val name = + val checkedName = if (tdef.name.hasVariance && tdef.mods.is(Param)) { ctx.error(em"type parameter name may not start with `+' or `-'", tdef.pos) ("$" + tdef.name).toTypeName } else tdef.name if (tdef.mods is PrivateLocalParam) { - val tparam = cpy.TypeDef(tdef)(name = tdef.name.expandedName(ctx.owner)) + val tparam = cpy.TypeDef(tdef)(name = checkedName.expandedName(ctx.owner)) .withMods(tdef.mods &~ PrivateLocal | ExpandedName) - val alias = cpy.TypeDef(tdef)(rhs = refOfDef(tparam)) + val alias = cpy.TypeDef(tdef)(name = checkedName, rhs = refOfDef(tparam)) .withMods(tdef.mods & VarianceFlags | PrivateLocalParamAccessor | Synthetic) Thicket(tparam, alias) } - else tdef + else cpy.TypeDef(tdef)(name = checkedName) } @sharable private val synthetic = Modifiers(Synthetic) From 950c7e2311f504444ee658b2e1244e9d23a164c5 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 15 Mar 2017 11:13:37 +0100 Subject: [PATCH 5/5] Drop name checking scheme for type parameters It was a red herring. Symbolic names are expanded anyway to $plus / $minus, so they can't be confused with a variance prefix. --- compiler/src/dotty/tools/dotc/ast/Desugar.scala | 12 +++--------- tests/neg/illegal-param-names.scala | 1 - 2 files changed, 3 insertions(+), 10 deletions(-) delete mode 100644 tests/neg/illegal-param-names.scala diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 497b3791ed8e..feaca721ea58 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -241,20 +241,14 @@ object desugar { * class C { type v C$T; type v T = C$T } */ def typeDef(tdef: TypeDef)(implicit ctx: Context): Tree = { - val checkedName = - if (tdef.name.hasVariance && tdef.mods.is(Param)) { - ctx.error(em"type parameter name may not start with `+' or `-'", tdef.pos) - ("$" + tdef.name).toTypeName - } - else tdef.name if (tdef.mods is PrivateLocalParam) { - val tparam = cpy.TypeDef(tdef)(name = checkedName.expandedName(ctx.owner)) + val tparam = cpy.TypeDef(tdef)(name = tdef.name.expandedName(ctx.owner)) .withMods(tdef.mods &~ PrivateLocal | ExpandedName) - val alias = cpy.TypeDef(tdef)(name = checkedName, rhs = refOfDef(tparam)) + val alias = cpy.TypeDef(tdef)(name = tdef.name, rhs = refOfDef(tparam)) .withMods(tdef.mods & VarianceFlags | PrivateLocalParamAccessor | Synthetic) Thicket(tparam, alias) } - else cpy.TypeDef(tdef)(name = checkedName) + else tdef } @sharable private val synthetic = Modifiers(Synthetic) diff --git a/tests/neg/illegal-param-names.scala b/tests/neg/illegal-param-names.scala deleted file mode 100644 index 9ca06798a0d6..000000000000 --- a/tests/neg/illegal-param-names.scala +++ /dev/null @@ -1 +0,0 @@ -class Test[++, --] // error // error