aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2017-03-04 17:27:10 +0100
committerMartin Odersky <odersky@gmail.com>2017-03-04 18:28:21 +0100
commit353a4d9f17b91d09dea3c9090c7a21e267372abe (patch)
tree08e1541da2f277c17da167ee6b9758a3f08e5f90
parent06d3f7aefa620ce006008955203d7f8f8dc7b605 (diff)
downloaddotty-353a4d9f17b91d09dea3c9090c7a21e267372abe.tar.gz
dotty-353a4d9f17b91d09dea3c9090c7a21e267372abe.tar.bz2
dotty-353a4d9f17b91d09dea3c9090c7a21e267372abe.zip
Drop named type parameters in classes
Drop the [type T] syntax, and what's associated to make it work. Motivation: It's an alternative way of doing things for which there seems to be little need. The implementation was provisional and bitrotted during the various iterations to introduce higher-kinded types. So in the end the complxity-cost for language and compiler was not worth the added benefit that [type T] parameters provide. Noe that we still accept _named arguments_ [A = T] in expressions; these are useful for specifying some parameters and letting others be inferred.
-rw-r--r--compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/core/Flags.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/core/SymDenotations.scala17
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeApplications.scala61
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeComparer.scala14
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeOps.scala14
-rw-r--r--compiler/src/dotty/tools/dotc/core/Types.scala8
-rw-r--r--compiler/src/dotty/tools/dotc/parsing/Parsers.scala34
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Namer.scala54
-rw-r--r--compiler/src/dotty/tools/dotc/typer/RefChecks.scala5
-rw-r--r--compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala22
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Typer.scala30
-rw-r--r--docs/docs/internals/syntax.md4
-rw-r--r--tests/neg/namedTypeParams.scala12
14 files changed, 56 insertions, 225 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
index 3aa20f15b..b3c50fb71 100644
--- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
+++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
@@ -253,9 +253,6 @@ trait ConstraintHandling {
if (fromBelow && isOrType(inst) && isFullyDefined(inst) && !isOrType(upperBound))
inst = ctx.harmonizeUnion(inst)
- // 3. If instance is from below, and upper bound has open named parameters
- // make sure the instance has all named parameters of the bound.
- if (fromBelow) inst = inst.widenToNamedTypeParams(param.namedTypeParams)
inst
}
diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala
index 63fbc98dc..d2a1c58f5 100644
--- a/compiler/src/dotty/tools/dotc/core/Flags.scala
+++ b/compiler/src/dotty/tools/dotc/core/Flags.scala
@@ -613,9 +613,6 @@ object Flags {
/** A private parameter accessor */
final val PrivateParamAccessor = allOf(Private, ParamAccessor)
- /** A type parameter introduced with [type ... ] */
- final val NamedTypeParam = allOf(TypeParam, ParamAccessor)
-
/** A local parameter */
final val ParamAndLocal = allOf(Param, Local)
diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
index a3475e14c..9b9caf8e7 100644
--- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -1086,9 +1086,6 @@ object SymDenotations {
/** The type parameters of a class symbol, Nil for all other symbols */
def typeParams(implicit ctx: Context): List[TypeSymbol] = Nil
- /** The named type parameters declared or inherited by this symbol */
- def namedTypeParams(implicit ctx: Context): Set[TypeSymbol] = Set()
-
/** The type This(cls), where cls is this class, NoPrefix for all other symbols */
def thisType(implicit ctx: Context): Type = NoPrefix
@@ -1226,11 +1223,9 @@ object SymDenotations {
/** TODO: Document why caches are supposedly safe to use */
private[this] var myTypeParams: List[TypeSymbol] = _
- private[this] var myNamedTypeParams: Set[TypeSymbol] = _
-
/** The type parameters in this class, in the order they appear in the current
* scope `decls`. This might be temporarily the incorrect order when
- * reading Scala2 pickled info. The problem is fixed by `updateTypeParams`
+ * reading Scala2 pickled info. The problem is fixed by `ensureTypeParamsInCorrectOrder`,
* which is called once an unpickled symbol has been completed.
*/
private def typeParamsFromDecls(implicit ctx: Context) =
@@ -1253,16 +1248,6 @@ object SymDenotations {
myTypeParams
}
- /** The named type parameters declared or inherited by this class */
- override final def namedTypeParams(implicit ctx: Context): Set[TypeSymbol] = {
- def computeNamedTypeParams: Set[TypeSymbol] =
- if (ctx.erasedTypes || is(Module)) Set() // fast return for modules to avoid scanning package decls
- else memberNames(abstractTypeNameFilter).map(name =>
- info.member(name).symbol.asType).filter(_.is(TypeParam, butNot = ExpandedName)).toSet
- if (myNamedTypeParams == null) myNamedTypeParams = computeNamedTypeParams
- myNamedTypeParams
- }
-
override protected[dotc] final def info_=(tp: Type) = {
super.info_=(tp)
myTypeParams = null // changing the info might change decls, and with it typeParams
diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala
index 70819e590..c713cd542 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala
@@ -246,67 +246,6 @@ class TypeApplications(val self: Type) extends AnyVal {
case _ => Nil
}
- /** The named type parameters declared or inherited by this type.
- * These are all uninstantiated named type parameters of this type or one
- * of its base types.
- */
- final def namedTypeParams(implicit ctx: Context): Set[TypeSymbol] = self match {
- case self: ClassInfo =>
- self.cls.namedTypeParams
- case self: RefinedType =>
- self.parent.namedTypeParams.filterNot(_.name == self.refinedName)
- case self: SingletonType =>
- Set()
- case self: TypeProxy =>
- self.underlying.namedTypeParams
- case _ =>
- Set()
- }
-
- /** The smallest supertype of this type that instantiated none of the named type parameters
- * in `params`. That is, for each named type parameter `p` in `params`, either there is
- * no type field named `p` in this type, or `p` is a named type parameter of this type.
- * The first case is important for the recursive case of AndTypes, because some of their operands might
- * be missing the named parameter altogether, but the AndType as a whole can still
- * contain it.
- */
- final def widenToNamedTypeParams(params: Set[TypeSymbol])(implicit ctx: Context): Type = {
-
- /** Is widening not needed for `tp`? */
- def isOK(tp: Type) = {
- val ownParams = tp.namedTypeParams
- def isMissingOrOpen(param: TypeSymbol) = {
- val ownParam = tp.nonPrivateMember(param.name).symbol
- !ownParam.exists || ownParams.contains(ownParam.asType)
- }
- params.forall(isMissingOrOpen)
- }
-
- /** Widen type by forming the intersection of its widened parents */
- def widenToParents(tp: Type) = {
- val parents = tp.parents.map(p =>
- tp.baseTypeWithArgs(p.symbol).widenToNamedTypeParams(params))
- parents.reduceLeft(ctx.typeComparer.andType(_, _))
- }
-
- if (isOK(self)) self
- else self match {
- case self @ AppliedType(tycon, args) if !isOK(tycon) =>
- widenToParents(self)
- case self: TypeRef if self.symbol.isClass =>
- widenToParents(self)
- case self: RefinedType =>
- val parent1 = self.parent.widenToNamedTypeParams(params)
- if (params.exists(_.name == self.refinedName)) parent1
- else self.derivedRefinedType(parent1, self.refinedName, self.refinedInfo)
- case self: TypeProxy =>
- self.superType.widenToNamedTypeParams(params)
- case self: AndOrType =>
- self.derivedAndOrType(
- self.tp1.widenToNamedTypeParams(params), self.tp2.widenToNamedTypeParams(params))
- }
- }
-
/** Is self type higher-kinded (i.e. of kind != "*")? */
def isHK(implicit ctx: Context): Boolean = self.dealias match {
case self: TypeRef => self.info.isHK
diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
index fca111702..b97dfe684 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -1264,22 +1264,10 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
}
}
- /** `op(tp1, tp2)` unless `tp1` and `tp2` are type-constructors with at least
- * some unnamed type parameters.
+ /** `op(tp1, tp2)` unless `tp1` and `tp2` are type-constructors.
* In the latter case, combine `tp1` and `tp2` under a type lambda like this:
*
* [X1, ..., Xn] -> op(tp1[X1, ..., Xn], tp2[X1, ..., Xn])
- *
- * Note: There is a tension between named and positional parameters here, which
- * is impossible to resolve completely. Say you have
- *
- * C[type T], D[type U]
- *
- * Then do you expand `C & D` to `[T] -> C[T] & D[T]` or not? Under the named
- * type parameter interpretation, this would be wrong whereas under the traditional
- * higher-kinded interpretation this would be required. The problem arises from
- * allowing both interpretations. A possible remedy is to be somehow stricter
- * in where we allow which interpretation.
*/
private def liftIfHK(tp1: Type, tp2: Type, op: (Type, Type) => Type, original: (Type, Type) => Type) = {
val tparams1 = tp1.typeParams
diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala
index 308e6e306..6c40794e3 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala
@@ -428,16 +428,10 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
case tp: TypeRef =>
tp
case tp @ RefinedType(tp1, name: TypeName, rinfo) =>
- rinfo match {
- case TypeAlias(TypeRef(pre, name1)) if name1 == name && (pre =:= cls.thisType) =>
- // Don't record refinements of the form X = this.X (These can arise using named parameters).
- typr.println(s"dropping refinement $tp")
- case _ =>
- val prevInfo = refinements(name)
- refinements = refinements.updated(name,
- if (prevInfo == null) tp.refinedInfo else prevInfo & tp.refinedInfo)
- formals = formals.updated(name, tp1.typeParamNamed(name))
- }
+ val prevInfo = refinements(name)
+ refinements = refinements.updated(name,
+ if (prevInfo == null) tp.refinedInfo else prevInfo & tp.refinedInfo)
+ formals = formals.updated(name, tp1.typeParamNamed(name))
normalizeToRef(tp1)
case _: ErrorType =>
defn.AnyType
diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala
index f56c6a286..9dd767a8e 100644
--- a/compiler/src/dotty/tools/dotc/core/Types.scala
+++ b/compiler/src/dotty/tools/dotc/core/Types.scala
@@ -549,13 +549,7 @@ object Types {
def goThis(tp: ThisType) = {
val d = go(tp.underlying)
- if (d.exists)
- if ((pre eq tp) && d.symbol.is(NamedTypeParam) && (d.symbol.owner eq tp.cls))
- // If we look for a named type parameter `P` in `C.this.P`, looking up
- // the fully applied self type of `C` will give as an info the alias type
- // `P = this.P`. We need to return a denotation with the underlying bounds instead.
- d.symbol.denot
- else d
+ if (d.exists) d
else
// There is a special case to handle:
// trait Super { this: Sub => private class Inner {} println(this.Inner) }
diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
index b27bff37a..65c7a290d 100644
--- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
+++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
@@ -805,7 +805,7 @@ object Parsers {
private def simpleTypeRest(t: Tree): Tree = in.token match {
case HASH => simpleTypeRest(typeProjection(t))
case LBRACKET => simpleTypeRest(atPos(startOffset(t)) {
- AppliedTypeTree(t, typeArgs(namedOK = true, wildOK = true)) })
+ AppliedTypeTree(t, typeArgs(namedOK = false, wildOK = true)) })
case _ => t
}
@@ -1664,7 +1664,7 @@ object Parsers {
/* -------- PARAMETERS ------------------------------------------- */
/** ClsTypeParamClause::= `[' ClsTypeParam {`,' ClsTypeParam} `]'
- * ClsTypeParam ::= {Annotation} [{Modifier} type] [`+' | `-']
+ * ClsTypeParam ::= {Annotation} [`+' | `-']
* id [HkTypeParamClause] TypeParamBounds
*
* DefTypeParamClause::= `[' DefTypeParam {`,' DefTypeParam} `]'
@@ -1680,25 +1680,17 @@ object Parsers {
def typeParam(): TypeDef = {
val isConcreteOwner = ownerKind == ParamOwner.Class || ownerKind == ParamOwner.Def
val start = in.offset
- var mods = annotsAsMods()
- if (ownerKind == ParamOwner.Class) {
- mods = modifiers(start = mods)
- mods =
- atPos(start, in.offset) {
- if (in.token == TYPE) {
- val mod = atPos(in.skipToken()) { Mod.Type() }
- (mods | Param | ParamAccessor).withAddedMod(mod)
- } else {
- if (mods.hasFlags) syntaxError(TypeParamsTypeExpected(mods, ident()))
- mods | Param | PrivateLocal
- }
- }
- }
- else mods = atPos(start) (mods | Param)
- if (ownerKind != ParamOwner.Def) {
- if (isIdent(nme.raw.PLUS)) mods |= Covariant
- else if (isIdent(nme.raw.MINUS)) mods |= Contravariant
- if (mods is VarianceFlags) in.nextToken()
+ val mods = atPos(start) {
+ annotsAsMods() | {
+ if (ownerKind == ParamOwner.Class) Param | PrivateLocal
+ else Param
+ } | {
+ if (ownerKind != ParamOwner.Def)
+ if (isIdent(nme.raw.PLUS)) { in.nextToken(); Covariant }
+ else if (isIdent(nme.raw.MINUS)) { in.nextToken(); Contravariant }
+ else EmptyFlags
+ else EmptyFlags
+ }
}
atPos(start, nameStart) {
val name =
diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala
index d5f171fe3..96660f15c 100644
--- a/compiler/src/dotty/tools/dotc/typer/Namer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala
@@ -753,11 +753,10 @@ class Namer { typer: Typer =>
/* Check parent type tree `parent` for the following well-formedness conditions:
* (1) It must be a class type with a stable prefix (@see checkClassTypeWithStablePrefix)
* (2) If may not derive from itself
- * (3) Overriding type parameters must be correctly forwarded. (@see checkTypeParamOverride)
- * (4) The class is not final
- * (5) If the class is sealed, it is defined in the same compilation unit as the current class
+ * (3) The class is not final
+ * (4) If the class is sealed, it is defined in the same compilation unit as the current class
*/
- def checkedParentType(parent: untpd.Tree, paramAccessors: List[Symbol]): Type = {
+ def checkedParentType(parent: untpd.Tree): Type = {
val ptype = parentType(parent)(ctx.superCallContext)
if (cls.isRefinementClass) ptype
else {
@@ -772,8 +771,6 @@ class Namer { typer: Typer =>
ctx.error(i"cyclic inheritance: $cls extends itself$addendum", parent.pos)
defn.ObjectType
}
- else if (!paramAccessors.forall(checkTypeParamOverride(pt, _)))
- defn.ObjectType
else {
val pclazz = pt.typeSymbol
if (pclazz.is(Final))
@@ -785,47 +782,7 @@ class Namer { typer: Typer =>
}
}
- /* Check that every parameter with the same name as a visible named parameter in the parent
- * class satisfies the following two conditions:
- * (1) The overriding parameter is also named (i.e. not local/name mangled).
- * (2) The overriding parameter is passed on directly to the parent parameter, or the
- * parent parameter is not fully defined.
- * @return true if conditions are satisfied, false otherwise.
- */
- def checkTypeParamOverride(parent: Type, paramAccessor: Symbol): Boolean = {
- var ok = true
- val pname = paramAccessor.name
-
- def illegal(how: String): Unit = {
- ctx.error(em"Illegal override of public type parameter $pname in $parent$how", paramAccessor.pos)
- ok = false
- }
-
- def checkAlias(tp: Type): Unit = tp match {
- case tp: RefinedType =>
- if (tp.refinedName == pname)
- tp.refinedInfo match {
- case TypeAlias(alias) =>
- alias match {
- case TypeRef(pre, name1) if name1 == pname && (pre =:= cls.thisType) =>
- // OK, parameter is passed on directly
- case _ =>
- illegal(em".\nParameter is both redeclared and instantiated with $alias.")
- }
- case _ => // OK, argument is not fully defined
- }
- else checkAlias(tp.parent)
- case _ =>
- }
- if (parent.nonPrivateMember(paramAccessor.name).symbol.is(Param))
- if (paramAccessor is Private)
- illegal("\nwith private parameter. Parameter definition needs to be prefixed with `type'.")
- else
- checkAlias(parent)
- ok
- }
-
- addAnnotations(denot.symbol, original)
+ addAnnotations(denot.symbol, original)
val selfInfo =
if (self.isEmpty) NoType
@@ -853,8 +810,7 @@ class Namer { typer: Typer =>
indexAndAnnotate(rest)(inClassContext(selfInfo))
- val tparamAccessors = decls.filter(_ is TypeParamAccessor).toList
- val parentTypes = ensureFirstIsClass(parents.map(checkedParentType(_, tparamAccessors)))
+ val parentTypes = ensureFirstIsClass(parents.map(checkedParentType(_)))
val parentRefs = ctx.normalizeToClassRefs(parentTypes, cls, decls)
typr.println(s"completing $denot, parents = $parents, parentTypes = $parentTypes, parentRefs = $parentRefs")
diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala
index 7c573d23c..23d05e087 100644
--- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala
+++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala
@@ -241,8 +241,6 @@ object RefChecks {
isDefaultGetter(member.name) || // default getters are not checked for compatibility
memberTp.overrides(otherTp)
- def domain(sym: Symbol): Set[Name] = sym.info.namedTypeParams.map(_.name)
-
//Console.println(infoString(member) + " overrides " + infoString(other) + " in " + clazz);//DEBUG
// return if we already checked this combination elsewhere
@@ -344,9 +342,6 @@ object RefChecks {
overrideError("cannot be used here - only term macros can override term macros")
} else if (!compatibleTypes) {
overrideError("has incompatible type" + err.whyNoMatchStr(memberTp, otherTp))
- } else if (member.isType && domain(member) != domain(other)) {
- overrideError("has different named type parameters: "+
- i"[${domain(member).toList}%, %] instead of [${domain(other).toList}%, %]")
} else {
checkOverrideDeprecated()
}
diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala
index 53ce5555b..6bf8dcbbc 100644
--- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala
+++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala
@@ -199,10 +199,7 @@ trait TypeAssigner {
}
}
else if (d.symbol is TypeParamAccessor)
- if (d.info.isAlias)
- ensureAccessible(d.info.bounds.hi, superAccess, pos)
- else // It's a named parameter, use the non-symbolic representation to pick up inherited versions as well
- d.symbol.owner.thisType.select(d.symbol.name)
+ ensureAccessible(d.info.bounds.hi, superAccess, pos)
else
ctx.makePackageObjPrefixExplicit(tpe withDenot d)
case _ =>
@@ -452,23 +449,10 @@ trait TypeAssigner {
}
def assignType(tree: untpd.AppliedTypeTree, tycon: Tree, args: List[Tree])(implicit ctx: Context) = {
+ assert(!hasNamedArg(args))
val tparams = tycon.tpe.typeParams
- lazy val ntparams = tycon.tpe.namedTypeParams
- def refineNamed(tycon: Type, arg: Tree) = arg match {
- case ast.Trees.NamedArg(name, argtpt) =>
- // Dotty deviation: importing ast.Trees._ and matching on NamedArg gives a cyclic ref error
- val tparam = tparams.find(_.paramName == name) match {
- case Some(tparam) => tparam
- case none => ntparams.find(_.name == name).getOrElse(NoSymbol)
- }
- if (tparam.isTypeParam) RefinedType(tycon, name, argtpt.tpe.toBounds(tparam))
- else errorType(i"$tycon does not have a parameter or abstract type member named $name", arg.pos)
- case _ =>
- errorType(s"named and positional type arguments may not be mixed", arg.pos)
- }
val ownType =
- if (hasNamedArg(args)) (tycon.tpe /: args)(refineNamed)
- else if (sameLength(tparams, args)) tycon.tpe.appliedTo(args.tpes)
+ if (sameLength(tparams, args)) tycon.tpe.appliedTo(args.tpes)
else wrongNumberOfTypeArgs(tycon.tpe, tparams, args, tree.pos)
tree.withType(ownType)
}
diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala
index 57e3c1b88..b2e9d639d 100644
--- a/compiler/src/dotty/tools/dotc/typer/Typer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala
@@ -1064,23 +1064,21 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
else {
var args = tree.args
- val args1 =
- if (hasNamedArg(args)) typedNamedArgs(args)
- else {
- if (args.length != tparams.length) {
- wrongNumberOfTypeArgs(tpt1.tpe, tparams, args, tree.pos)
- args = args.take(tparams.length)
- }
- def typedArg(arg: untpd.Tree, tparam: TypeParamInfo) = {
- val (desugaredArg, argPt) =
- if (ctx.mode is Mode.Pattern)
- (if (isVarPattern(arg)) desugar.patternVar(arg) else arg, tparam.paramBounds)
- else
- (arg, WildcardType)
- typed(desugaredArg, argPt)
- }
- args.zipWithConserve(tparams)(typedArg(_, _)).asInstanceOf[List[Tree]]
+ val args1 = {
+ if (args.length != tparams.length) {
+ wrongNumberOfTypeArgs(tpt1.tpe, tparams, args, tree.pos)
+ args = args.take(tparams.length)
+ }
+ def typedArg(arg: untpd.Tree, tparam: TypeParamInfo) = {
+ val (desugaredArg, argPt) =
+ if (ctx.mode is Mode.Pattern)
+ (if (isVarPattern(arg)) desugar.patternVar(arg) else arg, tparam.paramBounds)
+ else
+ (arg, WildcardType)
+ typed(desugaredArg, argPt)
}
+ args.zipWithConserve(tparams)(typedArg(_, _)).asInstanceOf[List[Tree]]
+ }
// check that arguments conform to bounds is done in phase PostTyper
assignType(cpy.AppliedTypeTree(tree)(tpt1, args1), tpt1, args1)
}
diff --git a/docs/docs/internals/syntax.md b/docs/docs/internals/syntax.md
index b7d5936c2..7f06cdc2a 100644
--- a/docs/docs/internals/syntax.md
+++ b/docs/docs/internals/syntax.md
@@ -126,7 +126,7 @@ InfixType ::= RefinedType {id [nl] RefinedType}
RefinedType ::= WithType {[nl] Refinement} RefinedTypeTree(t, ds)
WithType ::= AnnotType {‘with’ AnnotType} (deprecated)
AnnotType ::= SimpleType {Annotation} Annotated(t, annot)
-SimpleType ::= SimpleType (TypeArgs | NamedTypeArgs) AppliedTypeTree(t, args)
+SimpleType ::= SimpleType TypeArgs AppliedTypeTree(t, args)
| SimpleType ‘#’ id Select(t, name)
| StableId
| Path ‘.’ ‘type’ SingletonTypeTree(p)
@@ -240,7 +240,7 @@ ArgumentPatterns ::= ‘(’ [Patterns] ‘)’
### Type and Value Parameters
```ebnf
ClsTypeParamClause::= ‘[’ ClsTypeParam {‘,’ ClsTypeParam} ‘]’
-ClsTypeParam ::= {Annotation} [{Modifier} type] [‘+’ | ‘-’] TypeDef(Modifiers, name, tparams, bounds)
+ClsTypeParam ::= {Annotation} [‘+’ | ‘-’] TypeDef(Modifiers, name, tparams, bounds)
id [HkTypeParamClause] TypeParamBounds Bound(below, above, context)
DefTypeParamClause::= ‘[’ DefTypeParam {‘,’ DefTypeParam} ‘]’
diff --git a/tests/neg/namedTypeParams.scala b/tests/neg/namedTypeParams.scala
new file mode 100644
index 000000000..75bb1cd7e
--- /dev/null
+++ b/tests/neg/namedTypeParams.scala
@@ -0,0 +1,12 @@
+class C[T]
+class D[type T] // error: identifier expected, but `type` found
+
+object Test {
+
+ val x: C[T = Int] = // error: ']' expected, but `=` found // error
+ new C[T = Int] // error: ']' expected, but `=` found // error
+
+ class E extends C[T = Int] // error: ']' expected, but `=` found // error
+ class F extends C[T = Int]() // error: ']' expected, but `=` found // error
+
+}