From 353a4d9f17b91d09dea3c9090c7a21e267372abe Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 4 Mar 2017 17:27:10 +0100 Subject: 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. --- compiler/src/dotty/tools/dotc/typer/Namer.scala | 54 ++-------------------- .../src/dotty/tools/dotc/typer/RefChecks.scala | 5 -- .../src/dotty/tools/dotc/typer/TypeAssigner.scala | 22 ++------- compiler/src/dotty/tools/dotc/typer/Typer.scala | 30 ++++++------ 4 files changed, 22 insertions(+), 89 deletions(-) (limited to 'compiler/src/dotty/tools/dotc/typer') 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) } -- cgit v1.2.3