aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/typer/Applications.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/dotty/tools/dotc/typer/Applications.scala')
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala87
1 files changed, 55 insertions, 32 deletions
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index 794c7e752..f4936cff0 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -429,9 +429,9 @@ 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, args: List[untpd.Tree], resultType: Type)(implicit ctx: Context)
- extends TypedApply(app, fun, methRef, args, resultType) {
- def typedArg(arg: untpd.Tree, formal: Type): TypedArg = typed(arg, formal)
+ 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 treeToArg(arg: Tree): untpd.Tree = untpd.TypedSplice(arg)
}
@@ -462,7 +462,7 @@ trait Applications extends Compatibility { self: Typer =>
tryEither { implicit ctx =>
val app =
if (proto.argsAreTyped) new ApplyToTyped(tree, fun1, funRef, proto.typedArgs, pt)
- else new ApplyToUntyped(tree, fun1, funRef, tree.args, pt)
+ else new ApplyToUntyped(tree, fun1, funRef, proto, pt)
val result = app.result
ConstFold(result) orElse result
} { failed => fun1 match {
@@ -530,6 +530,26 @@ trait Applications extends Compatibility { self: Typer =>
def typedUnApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = track("typedUnApply") {
val Apply(qual, args) = tree
+ def notAnExtractor(tree: Tree) =
+ errorTree(tree, s"${qual.show} cannot be used as an extractor in a pattern because it lacks an unapply or unapplySeq method")
+
+ val unapply = {
+ val dummyArg = untpd.TypedSplice(dummyTreeOfType(WildcardType))
+ val unappProto = FunProto(dummyArg :: Nil, pt, this)
+ tryEither {
+ implicit ctx => typedExpr(untpd.Select(qual, nme.unapply), unappProto)
+ } {
+ s =>
+ tryEither {
+ implicit ctx => typedExpr(untpd.Select(qual, nme.unapplySeq), unappProto) // for backwards compatibility; will be dropped
+ } {
+ _ => notAnExtractor(s.value)
+ }
+ }
+ }
+
+ def fromScala2x = unapply.symbol.exists && (unapply.symbol.owner is Scala2x)
+
def unapplyArgs(unapplyResult: Type)(implicit ctx: Context): List[Type] = {
def recur(tp: Type): List[Type] = {
def extractorMemberType(name: Name) = {
@@ -547,8 +567,11 @@ trait Applications extends Compatibility { self: Typer =>
sels.takeWhile(_.exists).toList
}
def seqSelector = defn.RepeatedParamType.appliedTo(tp.elemType :: Nil)
-
- if (tp derivesFrom defn.ProductClass) productSelectors
+ def optionSelectors(tp: Type): List[Type] =
+ if (defn.isTupleType(tp)) tp.typeArgs else tp :: Nil
+ if (fromScala2x && (tp isRef defn.OptionClass) && tp.typeArgs.length == 1)
+ optionSelectors(tp.typeArgs.head)
+ else if (tp derivesFrom defn.ProductClass) productSelectors
else if (tp derivesFrom defn.SeqClass) seqSelector :: Nil
else if (tp isRef defn.BooleanClass) Nil
else if (extractorMemberType(nme.isDefined).exists &&
@@ -562,43 +585,42 @@ trait Applications extends Compatibility { self: Typer =>
recur(unapplyResult)
}
- def notAnExtractor(tree: Tree) =
- errorTree(tree, s"${qual.show} cannot be used as an extractor in a pattern because it lacks an unapply or unapplySeq method")
-
- val unapply = {
- val dummyArg = untpd.TypedSplice(dummyTreeOfType(WildcardType))
- val unappProto = FunProto(dummyArg :: Nil, pt, this)
- tryEither {
- implicit ctx => typedExpr(untpd.Select(qual, nme.unapply), unappProto)
- } {
- s =>
- tryEither {
- implicit ctx => typedExpr(untpd.Select(qual, nme.unapplySeq), unappProto) // for backwards compatibility; will be dropped
- } {
- _ => notAnExtractor(s.value)
- }
- }
- }
-
unapply.tpe.widen match {
case mt: MethodType if !mt.isDependent =>
val unapplyArgType = mt.paramTypes.head
+ println(s"unapp arg tpe = ${unapplyArgType.show}, pt = ${pt.show}")
val ownType =
if (pt <:< unapplyArgType) {
- assert(isFullyDefined(unapplyArgType))
+ fullyDefinedType(unapplyArgType, "extractor argument", tree.pos)
+ println(i"case 1 $unapplyArgType ${ctx.typerState.constraint}")
pt
}
- else if (unapplyArgType <:< widenForSelector(pt))
+ else if (unapplyArgType <:< widenForSelector(pt)) {
ctx.maximizeType(unapplyArgType) match {
- case None => unapplyArgType
case Some(tvar) =>
- errorType(
+ def msg =
s"""There is no best instantiation of pattern type ${unapplyArgType.show}
|that makes it a subtype of selector type ${pt.show}.
- |Non-variant type variable ${tvar.origin.show} cannot be uniquely instantiated.""".stripMargin,
- tree.pos)
+ |Non-variant type variable ${tvar.origin.show} cannot be uniquely instantiated.""".stripMargin
+ if (fromScala2x) {
+ // We can't issue an error here, because in Scala 2, ::[B] is invariant
+ // whereas List[+T] is covariant. According to the strict rule, a pattern
+ // match of a List[C] against a case x :: xs is illegal, because
+ // B cannot be uniquely instantiated. Of course :: should have been
+ // covariant in the first place, but in the Scala libraries it isn't.
+ // So for now we allow these kinds of patterns, even though they
+ // can open unsoundness holes. See SI-7952 for an example of the hole this opens.
+ if (ctx.settings.verbose.value) ctx.warning(msg, tree.pos)
+ }
+ else {
+ println(s" ${unapply.symbol.owner} ${unapply.symbol.owner is Scala2x}")
+ ctx.error(msg, tree.pos)
+ }
+ case _ =>
}
- else errorType(
+ println(i"case 2 $unapplyArgType ${ctx.typerState.constraint}")
+ unapplyArgType
+ } else errorType(
s"Pattern type ${unapplyArgType.show} is neither a subtype nor a supertype of selector type ${pt.show}",
tree.pos)
@@ -608,12 +630,13 @@ trait Applications extends Compatibility { self: Typer =>
case _ => args
}
if (argTypes.length != bunchedArgs.length) {
- ctx.error(s"wrong number of argument patterns for ${err.patternConstrStr(unapply)}", tree.pos)
+ ctx.error(i"wrong number of argument patterns for $qual; expected: ($argTypes%, %)", tree.pos)
argTypes = argTypes.take(args.length) ++
List.fill(argTypes.length - args.length)(WildcardType)
}
val typedArgs = (bunchedArgs, argTypes).zipped map (typed(_, _))
val result = cpy.UnApply(tree, unapply, typedArgs) withType ownType
+ println(s"typedargs = $typedArgs")
if ((ownType eq pt) || ownType.isError) result
else Typed(result, TypeTree(ownType))
case tp =>