diff options
author | odersky <odersky@gmail.com> | 2017-03-14 17:05:30 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-03-14 17:05:30 +0100 |
commit | 934da77590dad2003fe850b48b2ae01b427508f0 (patch) | |
tree | 42ded3e03ed2c16e1680ebaf72a49ad2964b2026 /compiler/src/dotty/tools/dotc/typer | |
parent | 1aad0a1433e1261af252d2240d63f6f01da65cef (diff) | |
parent | 3c22580feccca384e83465afd38d3df689c61f88 (diff) | |
download | dotty-934da77590dad2003fe850b48b2ae01b427508f0.tar.gz dotty-934da77590dad2003fe850b48b2ae01b427508f0.tar.bz2 dotty-934da77590dad2003fe850b48b2ae01b427508f0.zip |
Merge pull request #2079 from dotty-staging/depmeth2
Allow inter-parameter dependencies
Diffstat (limited to 'compiler/src/dotty/tools/dotc/typer')
8 files changed, 62 insertions, 20 deletions
diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index a65ef00cc..5dcf16b62 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -178,6 +178,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic => */ protected def normalizedFun: Tree + protected def typeOfArg(arg: Arg): Type + /** If constructing trees, pull out all parts of the function * which are not idempotent into separate prefix definitions */ @@ -380,8 +382,16 @@ trait Applications extends Compatibility { self: Typer with Dynamic => if (success) formals match { case formal :: formals1 => - def addTyped(arg: Arg, formal: Type) = + /** Add result of typing argument `arg` against parameter type `formal`. + * @return A type transformation to apply to all arguments following this one. + */ + def addTyped(arg: Arg, formal: Type): Type => Type = { addArg(typedArg(arg, formal), formal) + if (methodType.isParamDependent) + _.substParam(MethodParam(methodType, n), typeOfArg(arg)) + else + identity + } def missingArg(n: Int): Unit = { val pname = methodType.paramNames(n) @@ -395,8 +405,10 @@ trait Applications extends Compatibility { self: Typer with Dynamic => val getter = findDefaultGetter(n + numArgs(normalizedFun)) if (getter.isEmpty) missingArg(n) else { - addTyped(treeToArg(spliceMeth(getter withPos normalizedFun.pos, normalizedFun)), formal) - matchArgs(args1, formals1, n + 1) + val substParam = addTyped( + treeToArg(spliceMeth(getter withPos normalizedFun.pos, normalizedFun)), + formal) + matchArgs(args1, formals1.mapconserve(substParam), n + 1) } } @@ -420,8 +432,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic => case EmptyTree :: args1 => tryDefault(n, args1) case arg :: args1 => - addTyped(arg, formal) - matchArgs(args1, formals1, n + 1) + val substParam = addTyped(arg, formal) + matchArgs(args1, formals1.mapconserve(substParam), n + 1) case nil => tryDefault(n, args) } @@ -477,6 +489,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => def argType(arg: Tree, formal: Type): Type = normalize(arg.tpe, formal) def treeToArg(arg: Tree): Tree = arg def isVarArg(arg: Tree): Boolean = tpd.isWildcardStarArg(arg) + def typeOfArg(arg: Tree): Type = arg.tpe def harmonizeArgs(args: List[Tree]) = harmonize(args) } @@ -494,6 +507,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => def argType(arg: Type, formal: Type): Type = arg def treeToArg(arg: Tree): Type = arg.tpe def isVarArg(arg: Type): Boolean = arg.isRepeatedParam + def typeOfArg(arg: Type): Type = arg def harmonizeArgs(args: List[Type]) = harmonizeTypes(args) } @@ -592,6 +606,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => extends TypedApply(app, fun, methRef, proto.args, resultType) { def typedArg(arg: untpd.Tree, formal: Type): TypedArg = proto.typedArg(arg, formal.widenExpr) def treeToArg(arg: Tree): untpd.Tree = untpd.TypedSplice(arg) + def typeOfArg(arg: untpd.Tree) = proto.typeOfArg(arg) } /** Subclass of Application for type checking an Apply node with typed arguments. */ @@ -603,6 +618,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => // not match the abstract method in Application and an abstract class error results. def typedArg(arg: tpd.Tree, formal: Type): TypedArg = arg def treeToArg(arg: Tree): Tree = arg + def typeOfArg(arg: Tree) = arg.tpe } /** If `app` is a `this(...)` constructor call, the this-call argument context, @@ -1263,7 +1279,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic => def sizeFits(alt: TermRef, tp: Type): Boolean = tp match { case tp: PolyType => sizeFits(alt, tp.resultType) - case MethodType(_, ptypes) => + case tp: MethodType => + val ptypes = tp.paramTypes val numParams = ptypes.length def isVarArgs = ptypes.nonEmpty && ptypes.last.isRepeatedParam def hasDefault = alt.symbol.hasDefaultParams diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index f822f8893..b43391592 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -441,7 +441,6 @@ object Checking { case List(param) => if (param.is(Mutable)) ctx.error("value class parameter must not be a var", param.pos) - case _ => ctx.error("value class needs to have exactly one val parameter", clazz.pos) } @@ -625,6 +624,24 @@ trait Checking { case _ => } } + + /** Check that method parameter types do not reference their own parameter + * or later parameters in the same parameter section. + */ + def checkNoForwardDependencies(vparams: List[ValDef])(implicit ctx: Context): Unit = vparams match { + case vparam :: vparams1 => + val check = new TreeTraverser { + def traverse(tree: Tree)(implicit ctx: Context) = tree match { + case id: Ident if vparams.exists(_.symbol == id.symbol) => + ctx.error("illegal forward reference to method parameter", id.pos) + case _ => + traverseChildren(tree) + } + } + check.traverse(vparam.tpt) + checkNoForwardDependencies(vparams1) + case Nil => + } } trait NoChecking extends Checking { @@ -642,4 +659,5 @@ trait NoChecking extends Checking { override def checkNotSingleton(tpt: Tree, where: String)(implicit ctx: Context): Tree = tpt override def checkDerivedValueClass(clazz: Symbol, stats: List[Tree])(implicit ctx: Context) = () override def checkTraitInheritance(parentSym: Symbol, cls: ClassSymbol, pos: Position)(implicit ctx: Context) = () + override def checkNoForwardDependencies(vparams: List[ValDef])(implicit ctx: Context): Unit = () } diff --git a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala index e7e7ece78..57c1808c9 100644 --- a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala +++ b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala @@ -59,8 +59,8 @@ object EtaExpansion { */ def liftArgs(defs: mutable.ListBuffer[Tree], methRef: Type, args: List[Tree])(implicit ctx: Context) = methRef.widen match { - case MethodType(paramNames, paramTypes) => - (args, paramNames, paramTypes).zipped map { (arg, name, tp) => + case mt: MethodType => + (args, mt.paramNames, mt.paramTypes).zipped map { (arg, name, tp) => if (tp.isInstanceOf[ExprType]) arg else liftArg(defs, arg, if (name contains '$') "" else name.toString + "$") } diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index b588e3ae5..f7dd725c8 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -237,6 +237,12 @@ object ProtoTypes { typer.adapt(targ, formal, arg) } + /** The type of the argument `arg`. + * @pre `arg` has been typed before + */ + def typeOfArg(arg: untpd.Tree)(implicit ctx: Context): Type = + myTypedArg(arg).tpe + private var myTupled: Type = NoType /** The same proto-type but with all arguments combined in a single tuple */ diff --git a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala index 3252ead47..6080c6644 100644 --- a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala +++ b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala @@ -85,8 +85,8 @@ class ReTyper extends Typer { override def encodeName(tree: untpd.NameTree)(implicit ctx: Context) = tree override def handleUnexpectedFunType(tree: untpd.Apply, fun: Tree)(implicit ctx: Context): Tree = fun.tpe match { - case mt @ MethodType(_, formals) => - val args: List[Tree] = tree.args.zipWithConserve(formals)(typedExpr(_, _)).asInstanceOf[List[Tree]] + case mt: MethodType => + val args: List[Tree] = tree.args.zipWithConserve(mt.paramTypes)(typedExpr(_, _)).asInstanceOf[List[Tree]] assignType(untpd.cpy.Apply(tree)(fun, args), fun, args) case _ => super.handleUnexpectedFunType(tree, fun) diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 6bf8dcbbc..6e774e38e 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -315,10 +315,10 @@ trait TypeAssigner { def assignType(tree: untpd.Apply, fn: Tree, args: List[Tree])(implicit ctx: Context) = { val ownType = fn.tpe.widen match { - case fntpe @ MethodType(_, ptypes) => - if (sameLength(ptypes, args) || ctx.phase.prev.relaxedTyping) fntpe.instantiate(args.tpes) + case fntpe: MethodType => + if (sameLength(fntpe.paramTypes, args) || ctx.phase.prev.relaxedTyping) fntpe.instantiate(args.tpes) else - errorType(i"wrong number of arguments for $fntpe: ${fn.tpe}, expected: ${ptypes.length}, found: ${args.length}", tree.pos) + errorType(i"wrong number of arguments for $fntpe: ${fn.tpe}, expected: ${fntpe.paramTypes.length}, found: ${args.length}", tree.pos) case t => errorType(i"${err.exprStr(fn)} does not take parameters", tree.pos) } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index fd0c7c73d..d4a9744e4 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -672,8 +672,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit // this can type the greatest set of admissible closures. (pt.dealias.argTypesLo.init, pt.dealias.argTypesHi.last) case SAMType(meth) => - val mt @ MethodType(_, paramTypes) = meth.info - (paramTypes, mt.resultType) + val MethodTpe(_, formals, restpe) = meth.info + (formals, restpe) case _ => (List.range(0, defaultArity) map alwaysWildcardType, WildcardType) } @@ -1229,6 +1229,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit completeAnnotations(ddef, sym) val tparams1 = tparams mapconserve (typed(_).asInstanceOf[TypeDef]) val vparamss1 = vparamss nestedMapconserve (typed(_).asInstanceOf[ValDef]) + vparamss1.foreach(checkNoForwardDependencies) if (sym is Implicit) checkImplicitParamsNotSingletons(vparamss1) var tpt1 = checkSimpleKinded(typedType(tpt)) @@ -1287,10 +1288,10 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def maybeCall(ref: Tree, psym: Symbol, cinfo: Type): Tree = cinfo match { case cinfo: PolyType => maybeCall(ref, psym, cinfo.resultType) - case cinfo @ MethodType(Nil, _) if cinfo.resultType.isInstanceOf[ImplicitMethodType] => + case cinfo @ MethodType(Nil) if cinfo.resultType.isInstanceOf[ImplicitMethodType] => val icall = New(ref).select(nme.CONSTRUCTOR).appliedToNone typedExpr(untpd.TypedSplice(icall))(superCtx) - case cinfo @ MethodType(Nil, _) if !cinfo.resultType.isInstanceOf[MethodType] => + case cinfo @ MethodType(Nil) if !cinfo.resultType.isInstanceOf[MethodType] => ref case cinfo: MethodType => if (!ctx.erasedTypes) { // after constructors arguments are passed in super call. diff --git a/compiler/src/dotty/tools/dotc/typer/Variances.scala b/compiler/src/dotty/tools/dotc/typer/Variances.scala index 92bd9fd74..5a1745930 100644 --- a/compiler/src/dotty/tools/dotc/typer/Variances.scala +++ b/compiler/src/dotty/tools/dotc/typer/Variances.scala @@ -79,8 +79,8 @@ object Variances { varianceInType(parent)(tparam) & varianceInType(rinfo)(tparam) case tp: RecType => varianceInType(tp.parent)(tparam) - case tp @ MethodType(_, paramTypes) => - flip(varianceInTypes(paramTypes)(tparam)) & varianceInType(tp.resultType)(tparam) + case tp: MethodType => + flip(varianceInTypes(tp.paramTypes)(tparam)) & varianceInType(tp.resultType)(tparam) case ExprType(restpe) => varianceInType(restpe)(tparam) case tp @ HKApply(tycon, args) => |