Skip to content

Commit 6131175

Browse files
authored
Merge pull request #2050 from dotty-staging/drop-named-param
Drop named type parameters in classes
2 parents 06d3f7a + 5460046 commit 6131175

19 files changed

+60
-246
lines changed

compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,9 +253,6 @@ trait ConstraintHandling {
253253
if (fromBelow && isOrType(inst) && isFullyDefined(inst) && !isOrType(upperBound))
254254
inst = ctx.harmonizeUnion(inst)
255255

256-
// 3. If instance is from below, and upper bound has open named parameters
257-
// make sure the instance has all named parameters of the bound.
258-
if (fromBelow) inst = inst.widenToNamedTypeParams(param.namedTypeParams)
259256
inst
260257
}
261258

compiler/src/dotty/tools/dotc/core/Flags.scala

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -613,9 +613,6 @@ object Flags {
613613
/** A private parameter accessor */
614614
final val PrivateParamAccessor = allOf(Private, ParamAccessor)
615615

616-
/** A type parameter introduced with [type ... ] */
617-
final val NamedTypeParam = allOf(TypeParam, ParamAccessor)
618-
619616
/** A local parameter */
620617
final val ParamAndLocal = allOf(Param, Local)
621618

compiler/src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,9 +1086,6 @@ object SymDenotations {
10861086
/** The type parameters of a class symbol, Nil for all other symbols */
10871087
def typeParams(implicit ctx: Context): List[TypeSymbol] = Nil
10881088

1089-
/** The named type parameters declared or inherited by this symbol */
1090-
def namedTypeParams(implicit ctx: Context): Set[TypeSymbol] = Set()
1091-
10921089
/** The type This(cls), where cls is this class, NoPrefix for all other symbols */
10931090
def thisType(implicit ctx: Context): Type = NoPrefix
10941091

@@ -1226,11 +1223,9 @@ object SymDenotations {
12261223
/** TODO: Document why caches are supposedly safe to use */
12271224
private[this] var myTypeParams: List[TypeSymbol] = _
12281225

1229-
private[this] var myNamedTypeParams: Set[TypeSymbol] = _
1230-
12311226
/** The type parameters in this class, in the order they appear in the current
12321227
* scope `decls`. This might be temporarily the incorrect order when
1233-
* reading Scala2 pickled info. The problem is fixed by `updateTypeParams`
1228+
* reading Scala2 pickled info. The problem is fixed by `ensureTypeParamsInCorrectOrder`,
12341229
* which is called once an unpickled symbol has been completed.
12351230
*/
12361231
private def typeParamsFromDecls(implicit ctx: Context) =
@@ -1253,16 +1248,6 @@ object SymDenotations {
12531248
myTypeParams
12541249
}
12551250

1256-
/** The named type parameters declared or inherited by this class */
1257-
override final def namedTypeParams(implicit ctx: Context): Set[TypeSymbol] = {
1258-
def computeNamedTypeParams: Set[TypeSymbol] =
1259-
if (ctx.erasedTypes || is(Module)) Set() // fast return for modules to avoid scanning package decls
1260-
else memberNames(abstractTypeNameFilter).map(name =>
1261-
info.member(name).symbol.asType).filter(_.is(TypeParam, butNot = ExpandedName)).toSet
1262-
if (myNamedTypeParams == null) myNamedTypeParams = computeNamedTypeParams
1263-
myNamedTypeParams
1264-
}
1265-
12661251
override protected[dotc] final def info_=(tp: Type) = {
12671252
super.info_=(tp)
12681253
myTypeParams = null // changing the info might change decls, and with it typeParams

compiler/src/dotty/tools/dotc/core/TypeApplications.scala

Lines changed: 0 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -246,67 +246,6 @@ class TypeApplications(val self: Type) extends AnyVal {
246246
case _ => Nil
247247
}
248248

249-
/** The named type parameters declared or inherited by this type.
250-
* These are all uninstantiated named type parameters of this type or one
251-
* of its base types.
252-
*/
253-
final def namedTypeParams(implicit ctx: Context): Set[TypeSymbol] = self match {
254-
case self: ClassInfo =>
255-
self.cls.namedTypeParams
256-
case self: RefinedType =>
257-
self.parent.namedTypeParams.filterNot(_.name == self.refinedName)
258-
case self: SingletonType =>
259-
Set()
260-
case self: TypeProxy =>
261-
self.underlying.namedTypeParams
262-
case _ =>
263-
Set()
264-
}
265-
266-
/** The smallest supertype of this type that instantiated none of the named type parameters
267-
* in `params`. That is, for each named type parameter `p` in `params`, either there is
268-
* no type field named `p` in this type, or `p` is a named type parameter of this type.
269-
* The first case is important for the recursive case of AndTypes, because some of their operands might
270-
* be missing the named parameter altogether, but the AndType as a whole can still
271-
* contain it.
272-
*/
273-
final def widenToNamedTypeParams(params: Set[TypeSymbol])(implicit ctx: Context): Type = {
274-
275-
/** Is widening not needed for `tp`? */
276-
def isOK(tp: Type) = {
277-
val ownParams = tp.namedTypeParams
278-
def isMissingOrOpen(param: TypeSymbol) = {
279-
val ownParam = tp.nonPrivateMember(param.name).symbol
280-
!ownParam.exists || ownParams.contains(ownParam.asType)
281-
}
282-
params.forall(isMissingOrOpen)
283-
}
284-
285-
/** Widen type by forming the intersection of its widened parents */
286-
def widenToParents(tp: Type) = {
287-
val parents = tp.parents.map(p =>
288-
tp.baseTypeWithArgs(p.symbol).widenToNamedTypeParams(params))
289-
parents.reduceLeft(ctx.typeComparer.andType(_, _))
290-
}
291-
292-
if (isOK(self)) self
293-
else self match {
294-
case self @ AppliedType(tycon, args) if !isOK(tycon) =>
295-
widenToParents(self)
296-
case self: TypeRef if self.symbol.isClass =>
297-
widenToParents(self)
298-
case self: RefinedType =>
299-
val parent1 = self.parent.widenToNamedTypeParams(params)
300-
if (params.exists(_.name == self.refinedName)) parent1
301-
else self.derivedRefinedType(parent1, self.refinedName, self.refinedInfo)
302-
case self: TypeProxy =>
303-
self.superType.widenToNamedTypeParams(params)
304-
case self: AndOrType =>
305-
self.derivedAndOrType(
306-
self.tp1.widenToNamedTypeParams(params), self.tp2.widenToNamedTypeParams(params))
307-
}
308-
}
309-
310249
/** Is self type higher-kinded (i.e. of kind != "*")? */
311250
def isHK(implicit ctx: Context): Boolean = self.dealias match {
312251
case self: TypeRef => self.info.isHK

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,22 +1264,10 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
12641264
}
12651265
}
12661266

1267-
/** `op(tp1, tp2)` unless `tp1` and `tp2` are type-constructors with at least
1268-
* some unnamed type parameters.
1267+
/** `op(tp1, tp2)` unless `tp1` and `tp2` are type-constructors.
12691268
* In the latter case, combine `tp1` and `tp2` under a type lambda like this:
12701269
*
12711270
* [X1, ..., Xn] -> op(tp1[X1, ..., Xn], tp2[X1, ..., Xn])
1272-
*
1273-
* Note: There is a tension between named and positional parameters here, which
1274-
* is impossible to resolve completely. Say you have
1275-
*
1276-
* C[type T], D[type U]
1277-
*
1278-
* Then do you expand `C & D` to `[T] -> C[T] & D[T]` or not? Under the named
1279-
* type parameter interpretation, this would be wrong whereas under the traditional
1280-
* higher-kinded interpretation this would be required. The problem arises from
1281-
* allowing both interpretations. A possible remedy is to be somehow stricter
1282-
* in where we allow which interpretation.
12831271
*/
12841272
private def liftIfHK(tp1: Type, tp2: Type, op: (Type, Type) => Type, original: (Type, Type) => Type) = {
12851273
val tparams1 = tp1.typeParams

compiler/src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -428,16 +428,10 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
428428
case tp: TypeRef =>
429429
tp
430430
case tp @ RefinedType(tp1, name: TypeName, rinfo) =>
431-
rinfo match {
432-
case TypeAlias(TypeRef(pre, name1)) if name1 == name && (pre =:= cls.thisType) =>
433-
// Don't record refinements of the form X = this.X (These can arise using named parameters).
434-
typr.println(s"dropping refinement $tp")
435-
case _ =>
436-
val prevInfo = refinements(name)
437-
refinements = refinements.updated(name,
438-
if (prevInfo == null) tp.refinedInfo else prevInfo & tp.refinedInfo)
439-
formals = formals.updated(name, tp1.typeParamNamed(name))
440-
}
431+
val prevInfo = refinements(name)
432+
refinements = refinements.updated(name,
433+
if (prevInfo == null) tp.refinedInfo else prevInfo & tp.refinedInfo)
434+
formals = formals.updated(name, tp1.typeParamNamed(name))
441435
normalizeToRef(tp1)
442436
case _: ErrorType =>
443437
defn.AnyType

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -549,13 +549,7 @@ object Types {
549549

550550
def goThis(tp: ThisType) = {
551551
val d = go(tp.underlying)
552-
if (d.exists)
553-
if ((pre eq tp) && d.symbol.is(NamedTypeParam) && (d.symbol.owner eq tp.cls))
554-
// If we look for a named type parameter `P` in `C.this.P`, looking up
555-
// the fully applied self type of `C` will give as an info the alias type
556-
// `P = this.P`. We need to return a denotation with the underlying bounds instead.
557-
d.symbol.denot
558-
else d
552+
if (d.exists) d
559553
else
560554
// There is a special case to handle:
561555
// trait Super { this: Sub => private class Inner {} println(this.Inner) }

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,7 @@ object Parsers {
805805
private def simpleTypeRest(t: Tree): Tree = in.token match {
806806
case HASH => simpleTypeRest(typeProjection(t))
807807
case LBRACKET => simpleTypeRest(atPos(startOffset(t)) {
808-
AppliedTypeTree(t, typeArgs(namedOK = true, wildOK = true)) })
808+
AppliedTypeTree(t, typeArgs(namedOK = false, wildOK = true)) })
809809
case _ => t
810810
}
811811

@@ -1664,7 +1664,7 @@ object Parsers {
16641664
/* -------- PARAMETERS ------------------------------------------- */
16651665

16661666
/** ClsTypeParamClause::= `[' ClsTypeParam {`,' ClsTypeParam} `]'
1667-
* ClsTypeParam ::= {Annotation} [{Modifier} type] [`+' | `-']
1667+
* ClsTypeParam ::= {Annotation} [`+' | `-']
16681668
* id [HkTypeParamClause] TypeParamBounds
16691669
*
16701670
* DefTypeParamClause::= `[' DefTypeParam {`,' DefTypeParam} `]'
@@ -1680,25 +1680,17 @@ object Parsers {
16801680
def typeParam(): TypeDef = {
16811681
val isConcreteOwner = ownerKind == ParamOwner.Class || ownerKind == ParamOwner.Def
16821682
val start = in.offset
1683-
var mods = annotsAsMods()
1684-
if (ownerKind == ParamOwner.Class) {
1685-
mods = modifiers(start = mods)
1686-
mods =
1687-
atPos(start, in.offset) {
1688-
if (in.token == TYPE) {
1689-
val mod = atPos(in.skipToken()) { Mod.Type() }
1690-
(mods | Param | ParamAccessor).withAddedMod(mod)
1691-
} else {
1692-
if (mods.hasFlags) syntaxError(TypeParamsTypeExpected(mods, ident()))
1693-
mods | Param | PrivateLocal
1694-
}
1695-
}
1696-
}
1697-
else mods = atPos(start) (mods | Param)
1698-
if (ownerKind != ParamOwner.Def) {
1699-
if (isIdent(nme.raw.PLUS)) mods |= Covariant
1700-
else if (isIdent(nme.raw.MINUS)) mods |= Contravariant
1701-
if (mods is VarianceFlags) in.nextToken()
1683+
val mods = atPos(start) {
1684+
annotsAsMods() | {
1685+
if (ownerKind == ParamOwner.Class) Param | PrivateLocal
1686+
else Param
1687+
} | {
1688+
if (ownerKind != ParamOwner.Def)
1689+
if (isIdent(nme.raw.PLUS)) { in.nextToken(); Covariant }
1690+
else if (isIdent(nme.raw.MINUS)) { in.nextToken(); Contravariant }
1691+
else EmptyFlags
1692+
else EmptyFlags
1693+
}
17021694
}
17031695
atPos(start, nameStart) {
17041696
val name =

compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ public enum ErrorMessageID {
3232
ByNameParameterNotSupportedID,
3333
WrongNumberOfTypeArgsID,
3434
IllegalVariableInPatternAlternativeID,
35-
TypeParamsTypeExpectedID,
3635
IdentifierExpectedID,
3736
AuxConstructorNeedsNonImplicitParameterID,
3837
IncorrectRepeatedParameterSyntaxID,

compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -691,19 +691,6 @@ object messages {
691691
}
692692
}
693693

694-
case class TypeParamsTypeExpected(mods: untpd.Modifiers, identifier: TermName)(implicit ctx: Context)
695-
extends Message(TypeParamsTypeExpectedID) {
696-
val kind = "Syntax"
697-
val msg = hl"""Expected ${"type"} keyword for type parameter $identifier"""
698-
val explanation =
699-
hl"""|This happens when you add modifiers like ${"private"} or ${"protected"}
700-
|to your type parameter definition without adding the ${"type"} keyword.
701-
|
702-
|Add ${"type"} to your code, e.g.:
703-
|${s"trait A[${mods.flags} type $identifier]"}
704-
|"""
705-
}
706-
707694
case class IdentifierExpected(identifier: String)(implicit ctx: Context)
708695
extends Message(IdentifierExpectedID) {
709696
val kind = "Syntax"
@@ -1138,7 +1125,7 @@ object messages {
11381125
|
11391126
|You may want to create an anonymous class extending ${cls.name} with
11401127
| ${s"class ${cls.name} { }"}
1141-
|
1128+
|
11421129
|or add a companion object with
11431130
| ${s"object ${cls.name} extends ${cls.name}"}
11441131
|

compiler/src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 5 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -753,11 +753,10 @@ class Namer { typer: Typer =>
753753
/* Check parent type tree `parent` for the following well-formedness conditions:
754754
* (1) It must be a class type with a stable prefix (@see checkClassTypeWithStablePrefix)
755755
* (2) If may not derive from itself
756-
* (3) Overriding type parameters must be correctly forwarded. (@see checkTypeParamOverride)
757-
* (4) The class is not final
758-
* (5) If the class is sealed, it is defined in the same compilation unit as the current class
756+
* (3) The class is not final
757+
* (4) If the class is sealed, it is defined in the same compilation unit as the current class
759758
*/
760-
def checkedParentType(parent: untpd.Tree, paramAccessors: List[Symbol]): Type = {
759+
def checkedParentType(parent: untpd.Tree): Type = {
761760
val ptype = parentType(parent)(ctx.superCallContext)
762761
if (cls.isRefinementClass) ptype
763762
else {
@@ -772,8 +771,6 @@ class Namer { typer: Typer =>
772771
ctx.error(i"cyclic inheritance: $cls extends itself$addendum", parent.pos)
773772
defn.ObjectType
774773
}
775-
else if (!paramAccessors.forall(checkTypeParamOverride(pt, _)))
776-
defn.ObjectType
777774
else {
778775
val pclazz = pt.typeSymbol
779776
if (pclazz.is(Final))
@@ -785,47 +782,7 @@ class Namer { typer: Typer =>
785782
}
786783
}
787784

788-
/* Check that every parameter with the same name as a visible named parameter in the parent
789-
* class satisfies the following two conditions:
790-
* (1) The overriding parameter is also named (i.e. not local/name mangled).
791-
* (2) The overriding parameter is passed on directly to the parent parameter, or the
792-
* parent parameter is not fully defined.
793-
* @return true if conditions are satisfied, false otherwise.
794-
*/
795-
def checkTypeParamOverride(parent: Type, paramAccessor: Symbol): Boolean = {
796-
var ok = true
797-
val pname = paramAccessor.name
798-
799-
def illegal(how: String): Unit = {
800-
ctx.error(em"Illegal override of public type parameter $pname in $parent$how", paramAccessor.pos)
801-
ok = false
802-
}
803-
804-
def checkAlias(tp: Type): Unit = tp match {
805-
case tp: RefinedType =>
806-
if (tp.refinedName == pname)
807-
tp.refinedInfo match {
808-
case TypeAlias(alias) =>
809-
alias match {
810-
case TypeRef(pre, name1) if name1 == pname && (pre =:= cls.thisType) =>
811-
// OK, parameter is passed on directly
812-
case _ =>
813-
illegal(em".\nParameter is both redeclared and instantiated with $alias.")
814-
}
815-
case _ => // OK, argument is not fully defined
816-
}
817-
else checkAlias(tp.parent)
818-
case _ =>
819-
}
820-
if (parent.nonPrivateMember(paramAccessor.name).symbol.is(Param))
821-
if (paramAccessor is Private)
822-
illegal("\nwith private parameter. Parameter definition needs to be prefixed with `type'.")
823-
else
824-
checkAlias(parent)
825-
ok
826-
}
827-
828-
addAnnotations(denot.symbol, original)
785+
addAnnotations(denot.symbol, original)
829786

830787
val selfInfo =
831788
if (self.isEmpty) NoType
@@ -853,8 +810,7 @@ class Namer { typer: Typer =>
853810

854811
indexAndAnnotate(rest)(inClassContext(selfInfo))
855812

856-
val tparamAccessors = decls.filter(_ is TypeParamAccessor).toList
857-
val parentTypes = ensureFirstIsClass(parents.map(checkedParentType(_, tparamAccessors)))
813+
val parentTypes = ensureFirstIsClass(parents.map(checkedParentType(_)))
858814
val parentRefs = ctx.normalizeToClassRefs(parentTypes, cls, decls)
859815
typr.println(s"completing $denot, parents = $parents, parentTypes = $parentTypes, parentRefs = $parentRefs")
860816

compiler/src/dotty/tools/dotc/typer/RefChecks.scala

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,6 @@ object RefChecks {
241241
isDefaultGetter(member.name) || // default getters are not checked for compatibility
242242
memberTp.overrides(otherTp)
243243

244-
def domain(sym: Symbol): Set[Name] = sym.info.namedTypeParams.map(_.name)
245-
246244
//Console.println(infoString(member) + " overrides " + infoString(other) + " in " + clazz);//DEBUG
247245

248246
// return if we already checked this combination elsewhere
@@ -344,9 +342,6 @@ object RefChecks {
344342
overrideError("cannot be used here - only term macros can override term macros")
345343
} else if (!compatibleTypes) {
346344
overrideError("has incompatible type" + err.whyNoMatchStr(memberTp, otherTp))
347-
} else if (member.isType && domain(member) != domain(other)) {
348-
overrideError("has different named type parameters: "+
349-
i"[${domain(member).toList}%, %] instead of [${domain(other).toList}%, %]")
350345
} else {
351346
checkOverrideDeprecated()
352347
}

0 commit comments

Comments
 (0)