From c1c933d6f936a7975ca316c69d7639145eed36e7 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 17 Dec 2013 18:32:11 +0100 Subject: Fixes for by-name arguments Previously, we did not strip off the => when comparing against expected type. --- src/dotty/tools/dotc/core/TypeComparer.scala | 2 +- src/dotty/tools/dotc/core/Types.scala | 4 ++++ src/dotty/tools/dotc/typer/Applications.scala | 7 +++---- src/dotty/tools/dotc/typer/Implicits.scala | 3 ++- src/dotty/tools/dotc/typer/Inferencing.scala | 14 ++++++-------- tests/pos/Patterns.scala | 15 ++++++++++++++- 6 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index b441da6b4..84a9d84e7 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -72,7 +72,7 @@ class TypeComparer(initctx: Context) extends DotClass { def addConstraint(param: PolyParam, bound: Type, fromBelow: Boolean): Boolean = { param == bound || !frozenConstraint && { - println(s"adding ${param.show} ${if (fromBelow) ">:>" else "<:<"} ${bound.show} to ${constraint.show}") + // println(s"adding ${param.show} ${if (fromBelow) ">:>" else "<:<"} ${bound.show} to ${constraint.show}") bound match { case bound: PolyParam if constraint contains bound => addConstraint1(param, bound, fromBelow) && diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index a617f86d2..5976cf93b 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -550,6 +550,10 @@ object Types { case _ => this } + /** Widen from => T to T */ + final def widenByName(implicit ctx: Context): Type = + if (this isRef defn.ByNameParamClass) this.typeArgs.head else this + /** Widen type if it is unstable (i.e. an EpxprType, or Termref to unstable symbol */ final def widenIfUnstable(implicit ctx: Context): Type = this match { case tp: ExprType => tp.resultType.widenIfUnstable diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index 857ff31ff..6f65cd231 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -360,7 +360,7 @@ trait Applications extends Compatibility { self: Typer => init() def addArg(arg: Tree, formal: Type): Unit = - typedArgBuf += adaptInterpolated(arg, formal) + typedArgBuf += adaptInterpolated(arg, formal.widenByName) def makeVarArg(n: Int, elemFormal: Type): Unit = { val args = typedArgBuf.takeRight(n).toList @@ -411,7 +411,7 @@ trait Applications extends Compatibility { self: Typer => val result = { var typedArgs = typedArgBuf.toList - val ownType = ctx.traceIndented(i"apply $methRef to $typedArgs%, %", show = true) { + val ownType = if (!success) ErrorType else { if (!sameSeq(args, orderedArgs)) { @@ -426,7 +426,6 @@ trait Applications extends Compatibility { self: Typer => typedArgs = args.asInstanceOf[List[Tree]] methodType.instantiate(typedArgs.tpes) } - } wrapDefs(liftedDefs, cpy.Apply(app, normalizedFun, typedArgs).withType(ownType)) } } @@ -434,7 +433,7 @@ trait Applications extends Compatibility { self: Typer => /** Subclass of Application for type checking an Apply node with untyped arguments. */ class ApplyToUntyped(app: untpd.Apply, fun: Tree, methRef: TermRef, proto: FunProto, resultType: Type)(implicit ctx: Context) extends TypedApply(app, fun, methRef, proto.args, resultType) { - def typedArg(arg: untpd.Tree, formal: Type): TypedArg = proto.typedArg(arg, formal) + def typedArg(arg: untpd.Tree, formal: Type): TypedArg = proto.typedArg(arg, formal.widenByName) def treeToArg(arg: Tree): untpd.Tree = untpd.TypedSplice(arg) } diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala index 48b8bafe0..a6cbd58d1 100644 --- a/src/dotty/tools/dotc/typer/Implicits.scala +++ b/src/dotty/tools/dotc/typer/Implicits.scala @@ -263,13 +263,14 @@ trait Implicits { self: Typer => */ def inferImplicit(pt: Type, argument: Tree, pos: Position)(implicit ctx: Context): SearchResult = track("inferImplicit") { ctx.traceIndented(s"search implicit ${pt.show}, arg = ${argument.show}: ${argument.tpe.show}", show = true) { + assert(!(pt isRef defn.ByNameParamClass)) val isearch = if (ctx.settings.explaintypes.value) new ExplainedImplicitSearch(pt, argument, pos) else new ImplicitSearch(pt, argument, pos) val result = isearch.bestImplicit result match { case success: SearchSuccess => - println(s"committing to ${success.tstate.show}") + // println(s"committing to ${success.tstate.show}") success.tstate.commit() case _ => } diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala index 4d418fe97..418bf44d1 100644 --- a/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/src/dotty/tools/dotc/typer/Inferencing.scala @@ -29,11 +29,8 @@ object Inferencing { * 2. `pt` is by name parameter type, and `tp` is compatible with its underlying type * 3. there is an implicit conversion from `tp` to `pt`. */ - def isCompatible(tp: Type, pt: Type)(implicit ctx: Context): Boolean = { - def skipByName(tp: Type): Type = - if (tp isRef defn.ByNameParamClass) tp.typeArgs.head else tp - skipByName(tp) <:< skipByName(pt) || viewExists(tp, pt) - } + def isCompatible(tp: Type, pt: Type)(implicit ctx: Context): Boolean = + tp.widenByName <:< pt.widenByName || viewExists(tp, pt) /** Test compatibility after normalization in a fresh typerstate */ def normalizedCompatible(tp: Type, pt: Type)(implicit ctx: Context) = { @@ -313,18 +310,19 @@ object Inferencing { val tp = tree.tpe.widen val constraint = ctx.typerState.constraint + /* !!! DEBUG println(s"interpolate undet vars in ${tp.show}, pos = ${tree.pos}, mode = ${ctx.mode}, undets = ${constraint.uninstVars map (tvar => s"${tvar.show}@${tvar.owningTree.pos}")}") println(s"qualifying undet vars: ${constraint.uninstVars filter qualifies map (_.show)}") println(s"fulltype: $tp") // !!! DEBUG println(s"constraint: ${constraint.show}") + */ def qualifies(tvar: TypeVar) = tree contains tvar.owningTree val vs = tp.variances(tvar => (constraint contains tvar) && qualifies(tvar)) - println(s"variances = $vs") var changed = false vs foreachBinding { (tvar, v) => if (v != 0) { - println(s"interpolate ${if (v == 1) "co" else "contra"}variant ${tvar.show} in ${tp.show}") + //println(s"interpolate ${if (v == 1) "co" else "contra"}variant ${tvar.show} in ${tp.show}") tvar.instantiate(fromBelow = v == 1) changed = true } @@ -334,7 +332,7 @@ object Inferencing { else constraint.foreachUninstVar { tvar => if (!(vs contains tvar) && qualifies(tvar)) { - println(s"instantiating non-occurring $tvar in $tp") + //println(s"instantiating non-occurring $tvar in $tp") tvar.instantiate(fromBelow = true) } } diff --git a/tests/pos/Patterns.scala b/tests/pos/Patterns.scala index 1161e352b..fbcdc4c30 100644 --- a/tests/pos/Patterns.scala +++ b/tests/pos/Patterns.scala @@ -15,5 +15,18 @@ object Patterns { case Nil => 0 case x :: xs1 => x + sum(xs1) } - + + def len[T](xs: List[T]): Int = xs match { + case _ :: xs1 => 1 + len(xs1) + case Nil => 0 + } + + final def sameLength[T](xs: List[T], ys: List[T]): Boolean = xs match { + case _ :: xs1 => + ys match { + case _ :: ys1 => sameLength(xs1, ys1) + case _ => false + } + case _ => ys.isEmpty + } } \ No newline at end of file -- cgit v1.2.3