diff options
-rw-r--r-- | docs/SyntaxSummary.txt | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/parsing/Parsers.scala | 40 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/TypeAssigner.scala | 26 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 38 | ||||
-rw-r--r-- | tests/pickling/named-params.scala | 20 | ||||
-rw-r--r-- | tests/pos/named-params.scala | 17 |
6 files changed, 121 insertions, 24 deletions
diff --git a/docs/SyntaxSummary.txt b/docs/SyntaxSummary.txt index 11f23da94..78f59e6d1 100644 --- a/docs/SyntaxSummary.txt +++ b/docs/SyntaxSummary.txt @@ -103,7 +103,7 @@ grammar. RefinedType ::= WithType {[nl] Refinement} RefinedTypeTree(t, ds) WithType ::= AnnotType {`with' AnnotType} (deprecated) AnnotType ::= SimpleType {Annotation} Annotated(t, annot) - SimpleType ::= SimpleType TypeArgs AppliedTypeTree(t, args) + SimpleType ::= SimpleType (TypeArgs | NamedTypeArgs) AppliedTypeTree(t, args) | SimpleType `#' id SelectFromTypeTree(t, name) | StableId | Path `.' `type' SingletonTypeTree(p) @@ -118,6 +118,8 @@ grammar. ParamType ::= [`=>'] ParamValueType ParamValueType ::= Type [`*'] PostfixOp(t, "*") TypeArgs ::= `[' ArgTypes `]' ts + NamedTypeArg ::= id `=' ArgType NamedArg(id, t) + NamedTypeArgs ::= `[' NamedTypeArg {`,' NamedTypeArg} `]' nts Refinement ::= `{' [Dcl] {semi [Dcl]} `}' ds TypeBounds ::= [`>:' Type] [`<: Type] | INT TypeBoundsTree(lo, hi) TypeParamBounds ::= TypeBounds {`<%' Type} {`:' Type} ContextBounds(typeBounds, tps) diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala index 983ee1ccf..58ec75605 100644 --- a/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/src/dotty/tools/dotc/parsing/Parsers.scala @@ -740,7 +740,7 @@ object Parsers { private def simpleTypeRest(t: Tree): Tree = in.token match { case HASH => simpleTypeRest(typeProjection(t)) - case LBRACKET => simpleTypeRest(atPos(t.pos.start) { AppliedTypeTree(t, typeArgs()) }) + case LBRACKET => simpleTypeRest(atPos(t.pos.start) { AppliedTypeTree(t, typeArgs(namedOK = true)) }) case _ => t } @@ -759,9 +759,38 @@ object Parsers { } else typ() + /** NamedTypeArg ::= id `=' ArgType + */ + val namedTypeArg = () => { + val name = ident() + accept(EQUALS) + NamedArg(name.toTypeName, argType()) + } + /** ArgTypes ::= ArgType {`,' ArgType} + * NamedTypeArg {`,' NamedTypeArg} */ - def argTypes() = commaSeparated(argType) + def argTypes(namedOK: Boolean = false) = { + def otherArgs(first: Tree, arg: () => Tree): List[Tree] = { + val rest = + if (in.token == COMMA) { + in.nextToken() + commaSeparated(arg) + } + else Nil + first :: rest + } + if (namedOK && in.token == IDENTIFIER) + argType() match { + case Ident(name) if in.token == EQUALS => + in.nextToken() + otherArgs(NamedArg(name, argType()), namedTypeArg) + case firstArg => + if (in.token == EQUALS) println(s"??? $firstArg") + otherArgs(firstArg, argType) + } + else commaSeparated(argType) + } /** FunArgType ::= ArgType | `=>' ArgType */ @@ -785,9 +814,10 @@ object Parsers { } else t } - /** TypeArgs ::= `[' ArgType {`,' ArgType} `]' - */ - def typeArgs(): List[Tree] = inBrackets(argTypes()) + /** TypeArgs ::= `[' ArgType {`,' ArgType} `]' + * NamedTypeArgs ::= `[' NamedTypeArg {`,' NamedTypeArg} `]' + */ + def typeArgs(namedOK: Boolean = false): List[Tree] = inBrackets(argTypes(namedOK)) /** Refinement ::= `{' RefineStatSeq `}' */ diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala index ac46ee723..44ada642c 100644 --- a/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -4,6 +4,7 @@ package typer import core._ import ast._ +import ast.Trees._ import Scopes._, Contexts._, Constants._, Types._, Symbols._, Names._, Flags._, Decorators._ import ErrorReporting._, Annotations._, Denotations._, SymDenotations._, StdNames._, TypeErasure._ import util.Positions._ @@ -184,8 +185,11 @@ trait TypeAssigner { ErrorType } } - else if (d.symbol is TypeParamAccessor) // always dereference type param accessors - ensureAccessible(d.info.bounds.hi, superAccess, pos) + 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) else ctx.makePackageObjPrefixExplicit(tpe withDenot d) case _ => @@ -375,8 +379,24 @@ trait TypeAssigner { def assignType(tree: untpd.AppliedTypeTree, tycon: Tree, args: List[Tree])(implicit ctx: Context) = { val tparams = tycon.tpe.typeParams + def refineNamed(tycon: Type, arg: Tree) = arg match { + case NamedArg(name, argtpt) => + val tparam = tparams.find(_.name == name) match { + case Some(tparam) => tparam + case none => + val sym = tycon.member(name).symbol + if (sym.isAbstractType) sym + else if (sym.is(ParamAccessor)) sym.info.dealias.typeSymbol + else NoSymbol + } + if (tparam.exists) RefinedType(tycon, name, argtpt.tpe.toBounds(tparam)) + else errorType(s"$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 (sameLength(tparams, args)) tycon.tpe.appliedTo(args.tpes) + if (args.head.isInstanceOf[NamedArg]) (tycon.tpe /: args)(refineNamed) + else if (sameLength(tparams, args)) tycon.tpe.appliedTo(args.tpes) else errorType(d"wrong number of type arguments for ${tycon.tpe}, should be ${tparams.length}", tree.pos) tree.withType(ownType) } diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index d39f2dd43..42b556fa0 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -885,26 +885,34 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def typedAppliedTypeTree(tree: untpd.AppliedTypeTree)(implicit ctx: Context): Tree = track("typedAppliedTypeTree") { val tpt1 = typed(tree.tpt)(ctx retractMode Mode.Pattern) val tparams = tpt1.tpe.typeParams - var args = tree.args if (tparams.isEmpty) { ctx.error(d"${tpt1.tpe} does not take type parameters", tree.pos) tpt1 } else { - if (args.length != tparams.length) { - ctx.error(d"wrong number of type arguments for ${tpt1.tpe}, should be ${tparams.length}", tree.pos) - args = args.take(tparams.length) - } - def typedArg(arg: untpd.Tree, tparam: Symbol) = { - val (desugaredArg, argPt) = - if (ctx.mode is Mode.Pattern) - (if (isVarPattern(arg)) desugar.patternVar(arg) else arg, tparam.info) - else - (arg, WildcardType) - val arg1 = typed(desugaredArg, argPt) - adaptTypeArg(arg1, tparam.info) - } - val args1 = args.zipWithConserve(tparams)(typedArg(_, _)).asInstanceOf[List[Tree]] + var args = tree.args + val args1 = + if (args.head.isInstanceOf[untpd.NamedArg]) + for (arg @ NamedArg(id, argtpt) <- args) yield { + val argtpt1 = typedType(argtpt) + cpy.NamedArg(arg)(id, argtpt1).withType(argtpt1.tpe) + } + else { + if (args.length != tparams.length) { + ctx.error(d"wrong number of type arguments for ${tpt1.tpe}, should be ${tparams.length}", tree.pos) + args = args.take(tparams.length) + } + def typedArg(arg: untpd.Tree, tparam: Symbol) = { + val (desugaredArg, argPt) = + if (ctx.mode is Mode.Pattern) + (if (isVarPattern(arg)) desugar.patternVar(arg) else arg, tparam.info) + else + (arg, WildcardType) + val arg1 = typed(desugaredArg, argPt) + adaptTypeArg(arg1, tparam.info) + } + 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/tests/pickling/named-params.scala b/tests/pickling/named-params.scala new file mode 100644 index 000000000..e9346bb10 --- /dev/null +++ b/tests/pickling/named-params.scala @@ -0,0 +1,20 @@ +package namedparams + +abstract class C[type Elem, type Value](val elem: Elem) { + def toVal: Elem = ??? +} + + + +object Test { + val c = new C[String, String]("A") { + override def toVal = elem + } + val x: c.Elem = c.elem + + val c2: C { type Elem = String } = c + + val c3 = new C[Elem = String, Value = Int]("B") + val c4 = new C[Elem = String]("C") + val x2: c2.Elem = c2.elem +} diff --git a/tests/pos/named-params.scala b/tests/pos/named-params.scala new file mode 100644 index 000000000..51041078d --- /dev/null +++ b/tests/pos/named-params.scala @@ -0,0 +1,17 @@ +package namedparams + +abstract class C[type Elem, type Value](val elem: Elem) { + def toVal: Elem = ??? +} + + + +object Test { + val c = new C[String, String]("A") { + override def toVal = elem + } + val x: c.Elem = c.elem + + val c2: C { type Elem = String } = c + val x2: c2.Elem = c2.elem +} |