summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@epfl.ch>2011-01-20 09:43:18 +0000
committerAdriaan Moors <adriaan.moors@epfl.ch>2011-01-20 09:43:18 +0000
commitf0bff86d31c0ce9548e595c4b4b7fda8efe038c0 (patch)
treea01a425900de3bca3202bcfca1749099cb74a235 /src/compiler/scala/tools/nsc/typechecker
parentf4f1738fe79193010c328371521ed554e7e8cf6d (diff)
downloadscala-f0bff86d31c0ce9548e595c4b4b7fda8efe038c0.tar.gz
scala-f0bff86d31c0ce9548e595c4b4b7fda8efe038c0.tar.bz2
scala-f0bff86d31c0ce9548e595c4b4b7fda8efe038c0.zip
introduce NullaryMethodType to disambiguate Pol...
introduce NullaryMethodType to disambiguate PolyType motivation: given `def foo[T]: (T, T)` and `type Foo[T] = (T, T)`, `foo.info` and `TypeRef(_, Foo, Nil).normalize` are both `PolyType(List(T), Pair[T, T])` uncurry has been relying on an ugly hack to distinguish these cases based on ad-hoc kind inference without this distinction, the type alias's info (a type function) would be transformed to `PolyType(List(T), MethodType(Nil, Pair[T, T]))` anonymous type functions are being used more often (see #2741, #4017, #4079, #3443, #3106), which makes a proper treatment of PolyTypes more pressing change to type representation: PolyType(Nil, tp) -> NullaryMethodType(tp) PolyType(tps, tp) -> PolyType(tps, NullaryMethodType(tp)) (if the polytype denoted a polymorphic nullary method) PolyType(Nil, tp) is now invalid the kind of a PolyType is * iff its resulttype is a NullaryMethodType or a MethodType (i.e., it's a polymorphic value) in all other cases a PolyType now denotes a type constructor NullaryMethodType is eliminated during uncurry pickling: for backwards compatibility, a NullaryMethodType(tp) is still pickled as a PolyType(Nil, tp), unpickling rewrites pre-2.9-pickled PolyTypes according to the expected kind of the unpickled type (similar to what we used to do in uncurry) a pickled PolyType(Nil, restpe) is unpickled to NullaryMethodType(restpe) a pickled PolyType(tps, restpe) is unpickled to PolyType(tps, NullaryMethodType(restpe)) when the type is expected to have kind * the rewrite probably isn't complete, but was validated by compiling against the old scalacheck jar (which has plenty of polymorphic nullary methods) nevertheless, this commit includes a new scalacheck jar summary of the refactoring: * PolyType(List(), tp) or PolyType(Nil, tp) or PolyType(parms, tp) if params.isEmpty ==> NullaryMethodType(tp) * whenever there was a case PolyType(tps, tp) (irrespective of tps isEmpty), now need to consider the case PolyType(tps, NullaryMethodType(tp)); just add a case NullaryMethodType(tp), since usually: - there already is a PolyType case that recurses on the result type, - the polytype case applied to empty and non-empty type parameter lists alike * tp.resultType, where tp was assumed to be a PolyType that represents a polymorphic nullary method type before, tp == PolyType(tps, res), now tp == PolyType(tps, NullaryMethodType(res)) * got bitten again (last time was dependent-method types refactoring) by a TypeMap not being the identity when dropNonConstraintAnnotations is true (despite having an identity apply method). Since asSeenFrom is skipped when isTrivial, the annotations aren't dropped. The cps plugin relies on asSeenFrom dropping these annotations for trivial types though. Therefore, NullaryMethodType pretends to never be trivial. Better fix(?) in AsSeenFromMap: `if(tp.isTrivial) dropNonContraintAnnotations(tp) else ...` TODO: scalap and eclipse review by odersky, rytz
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala43
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala20
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala14
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala10
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Variances.scala2
9 files changed, 55 insertions, 48 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala b/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala
index c473df5333..34ba6f6da9 100644
--- a/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala
@@ -232,7 +232,7 @@ abstract class DeVirtualize /* extends InfoTransform with TypingTransformers {
val param = clazz.newMethod(clazz.pos, paramFieldName(clazz, index))
.setFlag(PROTECTED | LOCAL | DEFERRED | EXPANDEDNAME | SYNTHETIC | STABLE)
atPhase(ownPhase.next) {
- param.setInfo(PolyType(List(), tpe))
+ param.setInfo(NullaryMethodType(tpe))
}
param
}
@@ -294,7 +294,7 @@ abstract class DeVirtualize /* extends InfoTransform with TypingTransformers {
factory setInfo new PolyTypeCompleter(factory, clazz) {
private def copyType(tpe: Type): Type = tpe match {
case MethodType(formals, restpe) => MethodType(formals, copyType(restpe))
- case PolyType(List(), restpe) => PolyType(List(), copyType(restpe))
+ case NullaryMethodType(restpe) => NullaryMethodType(copyType(restpe))
case PolyType(_, _) => abort("bad case: "+tpe)
case _ => owner.thisType.memberType(abstractType(clazz))
}
@@ -394,7 +394,7 @@ abstract class DeVirtualize /* extends InfoTransform with TypingTransformers {
case (pt, i) =>
val pfield = cclazz.newMethod(cclazz.pos, paramFieldName(clazz, i))
.setFlag(PROTECTED | LOCAL | EXPANDEDNAME | SYNTHETIC | STABLE)
- .setInfo(PolyType(List(), pt))
+ .setInfo(NullaryMethodType(pt))
cclazz.info.decls enter pfield
atPos(factory.pos) {
DefDef(pfield, Ident(fixParamName(i)))
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 6a708a873c..8ad6830e4c 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -114,6 +114,8 @@ trait Implicits {
private def containsError(tp: Type): Boolean = tp match {
case PolyType(tparams, restpe) =>
containsError(restpe)
+ case NullaryMethodType(restpe) =>
+ containsError(restpe)
case MethodType(params, restpe) =>
params.exists(_.tpe.isError) || containsError(restpe)
case _ =>
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 84c770b553..15996923b2 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -175,7 +175,7 @@ trait Infer {
normalize(restpe)
case mt @ MethodType(params, restpe) if !restpe.isDependent =>
functionType(params map (_.tpe), normalize(restpe))
- case PolyType(List(), restpe) => // nullary method type
+ case NullaryMethodType(restpe) =>
normalize(restpe)
case ExistentialType(tparams, qtpe) =>
ExistentialType(tparams, normalize(qtpe))
@@ -350,6 +350,7 @@ trait Infer {
case tr: TypeRef => mtcheck(mt, tr)
case _ => lastChanceCheck(tp, pt)
}
+ case NullaryMethodType(restpe) => apply(restpe, pt)
case PolyType(_, restpe) => apply(restpe, pt)
case ExistentialType(_, qtpe) => apply(qtpe, pt)
case _ => argumentCheck(tp, pt)
@@ -367,7 +368,6 @@ trait Infer {
def lastChanceCheck(tp: Type, pt: Type) = tp <:< pt
override def apply(tp: Type, pt: Type): Boolean = tp match {
- case PolyType(tparams, restpe) => tparams.isEmpty && normSubType(restpe, pt)
case ExistentialType(_, _) => normalize(tp) <:< pt
case _ => super.apply(tp, pt)
}
@@ -659,7 +659,7 @@ trait Infer {
}
private[typechecker] def followApply(tp: Type): Type = tp match {
- case PolyType(List(), restp) =>
+ case NullaryMethodType(restp) =>
val restp1 = followApply(restp)
if (restp1 eq restp) tp else restp1
case _ =>
@@ -816,6 +816,8 @@ trait Infer {
else tryTupleApply
}
+ case NullaryMethodType(restpe) => // strip nullary method type, which used to be done by the polytype case below
+ isApplicable(undetparams, restpe, argtpes0, pt)
case PolyType(tparams, restpe) =>
val tparams1 = cloneSymbols(tparams)
isApplicable(tparams1 ::: undetparams, restpe.substSym(tparams, tparams1), argtpes0, pt)
@@ -860,18 +862,24 @@ trait Infer {
case et: ExistentialType =>
isAsSpecific(ftpe1.skolemizeExistential, ftpe2)
//et.withTypeVars(isAsSpecific(_, ftpe2))
+ case NullaryMethodType(res) =>
+ isAsSpecific(res, ftpe2)
case mt: MethodType if mt.isImplicit =>
isAsSpecific(ftpe1.resultType, ftpe2)
- case MethodType(params @ (x :: xs), _) =>
+ case MethodType(params, _) if params nonEmpty =>
var argtpes = params map (_.tpe)
if (isVarArgsList(params) && isVarArgsList(ftpe2.params))
argtpes = argtpes map (argtpe =>
if (isRepeatedParamType(argtpe)) argtpe.typeArgs.head else argtpe)
isApplicable(List(), ftpe2, argtpes, WildcardType)
+ case PolyType(tparams, NullaryMethodType(res)) =>
+ isAsSpecific(PolyType(tparams, res), ftpe2)
case PolyType(tparams, mt: MethodType) if mt.isImplicit =>
isAsSpecific(PolyType(tparams, mt.resultType), ftpe2)
- case PolyType(_, MethodType(params @ (x :: xs), _)) =>
+ case PolyType(_, MethodType(params, _)) if params nonEmpty =>
isApplicable(List(), ftpe2, params map (_.tpe), WildcardType)
+ // case NullaryMethodType(res) =>
+ // isAsSpecific(res, ftpe2)
case ErrorType =>
true
case _ =>
@@ -882,12 +890,25 @@ trait Infer {
et.withTypeVars(isAsSpecific(ftpe1, _))
case mt: MethodType =>
!mt.isImplicit || isAsSpecific(ftpe1, mt.resultType)
+ case NullaryMethodType(res) =>
+ isAsSpecific(ftpe1, res)
+ case PolyType(tparams, NullaryMethodType(res)) =>
+ isAsSpecific(ftpe1, PolyType(tparams, res))
case PolyType(tparams, mt: MethodType) =>
!mt.isImplicit || isAsSpecific(ftpe1, PolyType(tparams, mt.resultType))
case _ =>
isAsSpecificValueType(ftpe1, ftpe2, List(), List())
}
}
+ private def isAsSpecificValueType(tpe1: Type, tpe2: Type, undef1: List[Symbol], undef2: List[Symbol]): Boolean = (tpe1, tpe2) match {
+ case (PolyType(tparams1, rtpe1), _) =>
+ isAsSpecificValueType(rtpe1, tpe2, undef1 ::: tparams1, undef2)
+ case (_, PolyType(tparams2, rtpe2)) =>
+ isAsSpecificValueType(tpe1, rtpe2, undef1, undef2 ::: tparams2)
+ case _ =>
+ existentialAbstraction(undef1, tpe1) <:< existentialAbstraction(undef2, tpe2)
+ }
+
/*
def isStrictlyMoreSpecific(ftpe1: Type, ftpe2: Type): Boolean =
@@ -943,16 +964,6 @@ trait Infer {
case _ =>
false
}
-
- private def isAsSpecificValueType(tpe1: Type, tpe2: Type, undef1: List[Symbol], undef2: List[Symbol]): Boolean = (tpe1, tpe2) match {
- case (PolyType(tparams1, rtpe1), _) =>
- isAsSpecificValueType(rtpe1, tpe2, undef1 ::: tparams1, undef2)
- case (_, PolyType(tparams2, rtpe2)) =>
- isAsSpecificValueType(tpe1, rtpe2, undef1, undef2 ::: tparams2)
- case _ =>
- existentialAbstraction(undef1, tpe1) <:< existentialAbstraction(undef2, tpe2)
- }
-
/*
/** Is type `tpe1' a strictly better expression alternative than type `tpe2'?
*/
@@ -1120,7 +1131,7 @@ trait Infer {
if (targs eq null) {
if (!tree.tpe.isErroneous && !pt.isErroneous)
error(tree.pos, "polymorphic expression cannot be instantiated to expected type" +
- foundReqMsg(PolyType(undetparams, skipImplicit(tree.tpe)), pt))
+ foundReqMsg(polyType(undetparams, skipImplicit(tree.tpe)), pt))
} else {
new TreeTypeSubstituter(undetparams, targs).traverse(tree)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 775731df2b..9b27b35e82 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -578,7 +578,7 @@ trait Namers { self: Analyzer =>
def getterTypeCompleter(vd: ValDef) = mkTypeCompleter(vd) { sym =>
if (settings.debug.value) log("defining " + sym)
val tp = typeSig(vd)
- sym.setInfo(PolyType(List(), tp))
+ sym.setInfo(NullaryMethodType(tp))
if (settings.debug.value) log("defined " + sym)
validate(sym)
}
@@ -862,7 +862,7 @@ trait Namers { self: Analyzer =>
polyType(
tparamSyms, // deSkolemized symbols -- TODO: check that their infos don't refer to method args?
- if (vparamSymss.isEmpty) PolyType(List(), restpe) // nullary method type
+ if (vparamSymss.isEmpty) NullaryMethodType(restpe)
// vparamss refer (if they do) to skolemized tparams
else (vparamSymss :\ restpe) (makeMethodType))
}
@@ -907,7 +907,7 @@ trait Namers { self: Analyzer =>
resultPt = resultPt.resultType
}
resultPt match {
- case PolyType(List(), rtpe) => resultPt = rtpe
+ case NullaryMethodType(rtpe) => resultPt = rtpe
case MethodType(List(), rtpe) => resultPt = rtpe
case _ =>
}
@@ -1264,22 +1264,8 @@ trait Namers { self: Analyzer =>
}
result match {
case PolyType(tparams @ (tp :: _), _) if tp.owner.isTerm =>
- // ||
- // Adriaan: The added condition below is quite a hack. It seems that HK type parameters is relying
- // on a pass that forces all infos in the type to get everything right.
- // The problem is that the same pass causes cyclic reference errors in
- // test pos/cyclics.scala. It turned out that deSkolemize is run way more often than necessary,
- // running it only when needed fixes the cyclic reference errors.
- // But correcting deSkolemize broke HK types, because we don't do the traversal anymore.
- // For the moment I made a special hack to do the traversal if we have HK type parameters.
- // Maybe it's not a hack, then we need to document it better. But ideally, we should find
- // a way to deal with HK types that's not dependent on accidental side
- // effects like this.
- // tparams.exists(!_.typeParams.isEmpty)) =>
new DeSkolemizeMap(tparams) mapOver result
case _ =>
-// println("not skolemizing "+result+" in "+context.owner)
-// new DeSkolemizeMap(List()) mapOver result
result
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index adc7813b9c..df8ec9c762 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -66,7 +66,7 @@ abstract class RefChecks extends InfoTransform {
sym.setFlag(LAZY | ACCESSOR)
}
}
- PolyType(List(), tp)
+ NullaryMethodType(tp)
} else tp
}
@@ -244,12 +244,12 @@ abstract class RefChecks extends InfoTransform {
}
def overridesType(tp1: Type, tp2: Type): Boolean = (tp1.normalize, tp2.normalize) match {
- case (MethodType(List(), rtp1), PolyType(List(), rtp2)) =>
+ case (MethodType(List(), rtp1), NullaryMethodType(rtp2)) =>
rtp1 <:< rtp2
- case (PolyType(List(), rtp1), MethodType(List(), rtp2)) =>
+ case (NullaryMethodType(rtp1), MethodType(List(), rtp2)) =>
rtp1 <:< rtp2
case (TypeRef(_, sym, _), _) if (sym.isModuleClass) =>
- overridesType(PolyType(List(), tp1), tp2)
+ overridesType(NullaryMethodType(tp1), tp2)
case _ =>
tp1 <:< tp2
}
@@ -753,6 +753,8 @@ abstract class RefChecks extends InfoTransform {
validateVariance(hi, variance)
case MethodType(formals, result) =>
validateVariance(result, variance)
+ case NullaryMethodType(result) =>
+ validateVariance(result, variance)
case PolyType(tparams, result) =>
// type parameters will be validated separately, because they are defined explicitly.
validateVariance(result, variance)
@@ -1006,7 +1008,7 @@ abstract class RefChecks extends InfoTransform {
if (!sym.allOverriddenSymbols.isEmpty) {
val factory = sym.owner.newMethod(sym.pos, sym.name.toTermName)
.setFlag(sym.flags | STABLE).resetFlag(MODULE)
- .setInfo(PolyType(List(), sym.moduleClass.tpe))
+ .setInfo(NullaryMethodType(sym.moduleClass.tpe))
sym.owner.info.decls.enter(factory)
val ddef =
atPhase(phase.next) {
@@ -1043,7 +1045,7 @@ abstract class RefChecks extends InfoTransform {
sym.resetFlag(MODULE | FINAL | CASE)
sym.setFlag(LAZY | ACCESSOR | SYNTHETIC)
- sym.setInfo(PolyType(List(), sym.tpe))
+ sym.setInfo(NullaryMethodType(sym.tpe))
sym setFlag (lateMETHOD | STABLE)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index 3e8f7bd2c7..6f3bb9e976 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -103,7 +103,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
var superAccTpe = clazz.thisType.memberType(sym)
if (sym.isModule && !sym.isMethod) {
// the super accessor always needs to be a method. See #231
- superAccTpe = PolyType(List(), superAccTpe)
+ superAccTpe = NullaryMethodType(superAccTpe)
}
superAcc.setInfo(superAccTpe.cloneInfo(superAcc))
//println("creating super acc "+superAcc+":"+superAcc.tpe)//DEBUG
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index 2d544ba1d1..03b080398f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -86,12 +86,12 @@ trait SyntheticMethods extends ast.TreeDSL {
import CODE._
def productPrefixMethod: Tree = typer.typed {
- val method = syntheticMethod(nme.productPrefix, 0, sym => PolyType(Nil, StringClass.tpe))
+ val method = syntheticMethod(nme.productPrefix, 0, sym => NullaryMethodType(StringClass.tpe))
DEF(method) === LIT(clazz.name.decode)
}
def productArityMethod(nargs: Int): Tree = {
- val method = syntheticMethod(nme.productArity, 0, sym => PolyType(Nil, IntClass.tpe))
+ val method = syntheticMethod(nme.productArity, 0, sym => NullaryMethodType(IntClass.tpe))
typer typed { DEF(method) === LIT(nargs) }
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 3337584420..19fc981035 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -568,6 +568,7 @@ trait Typers extends Modes {
case ExistentialType(_, tpe1) => isNarrowable(tpe1)
case AnnotatedType(_, tpe1, _) => isNarrowable(tpe1)
case PolyType(_, tpe1) => isNarrowable(tpe1)
+ case NullaryMethodType(tpe1) => isNarrowable(tpe1)
case _ => !phase.erasedTypes
}
@@ -702,7 +703,7 @@ trait Typers extends Modes {
case OverloadedType(pre, alts) if !inFunMode(mode) => // (1)
inferExprAlternative(tree, pt)
adapt(tree, mode, pt, original)
- case PolyType(List(), restpe) => // (2)
+ case NullaryMethodType(restpe) => // (2)
adapt(tree setType restpe, mode, pt, original)
case TypeRef(_, ByNameParamClass, List(arg))
if ((mode & EXPRmode) != 0) => // (2)
@@ -1591,6 +1592,8 @@ trait Typers extends Modes {
if (meth.owner.isStructuralRefinement && meth.allOverriddenSymbols.isEmpty && !(meth.isPrivate || meth.hasAccessBoundary)) {
val tp: Type = meth.tpe match {
case mt: MethodType => mt
+ case NullaryMethodType(res) => res
+ // TODO_NMT: drop NullaryMethodType from resultType?
case pt: PolyType => pt.resultType
case _ => NoType
}
@@ -1624,7 +1627,7 @@ trait Typers extends Modes {
case tpt: Tree =>
val alias = enclClass.newAliasType(useCase.pos, name.toTypeName)
val tparams = cloneSymbols(tpt.tpe.typeSymbol.typeParams, alias)
- alias setInfo polyType(tparams, appliedType(tpt.tpe, tparams map (_.tpe)))
+ alias setInfo typeFun(tparams, appliedType(tpt.tpe, tparams map (_.tpe)))
context.scope.enter(alias)
case _ =>
}
@@ -2175,6 +2178,7 @@ trait Typers extends Modes {
}
def doTypedApply(tree: Tree, fun0: Tree, args: List[Tree], mode: Int, pt: Type): Tree = {
+ // TODO_NMT: check the assumption that args nonEmpty
var fun = fun0
if (fun.hasSymbol && fun.symbol.isOverloaded) {
// remove alternatives with wrong number of parameters without looking at types.
@@ -3148,7 +3152,7 @@ trait Typers extends Modes {
val expr2 = Function(List(), expr1) setPos expr1.pos
new ChangeOwnerTraverser(context.owner, expr2.symbol).traverse(expr2)
typed1(expr2, mode, pt)
- case PolyType(List(), restpe) =>
+ case NullaryMethodType(restpe) =>
val expr2 = Function(List(), expr1) setPos expr1.pos
new ChangeOwnerTraverser(context.owner, expr2.symbol).traverse(expr2)
typed1(expr2, mode, pt)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Variances.scala b/src/compiler/scala/tools/nsc/typechecker/Variances.scala
index 4ad5c9057f..e29d96e663 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Variances.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Variances.scala
@@ -78,6 +78,8 @@ trait Variances {
varianceInTypes(parents)(tparam) & varianceInSyms(defs.toList)(tparam)
case MethodType(params, restpe) =>
flip(varianceInSyms(params)(tparam)) & varianceInType(restpe)(tparam)
+ case NullaryMethodType(restpe) =>
+ varianceInType(restpe)(tparam)
case PolyType(tparams, restpe) =>
flip(varianceInSyms(tparams)(tparam)) & varianceInType(restpe)(tparam)
case ExistentialType(tparams, restpe) =>