summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Typers.scala
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@epfl.ch>2007-04-06 09:23:03 +0000
committerAdriaan Moors <adriaan.moors@epfl.ch>2007-04-06 09:23:03 +0000
commite1c732db445d1ab0172bc25073ce865acc7d280b (patch)
tree4e1445535167194e09815e95563e4d2a9ef927f3 /src/compiler/scala/tools/nsc/typechecker/Typers.scala
parent289fd3d7307ca117a419e71e3a20b0b811a0d33f (diff)
downloadscala-e1c732db445d1ab0172bc25073ce865acc7d280b.tar.gz
scala-e1c732db445d1ab0172bc25073ce865acc7d280b.tar.bz2
scala-e1c732db445d1ab0172bc25073ce865acc7d280b.zip
merged in tcpoly branch (at r10641)
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Typers.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala132
1 files changed, 105 insertions, 27 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index b54d378eb7..329eb344c6 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -239,8 +239,9 @@ trait Typers requires Analyzer {
tp match {
case TypeRef(pre, sym, args) =>
(checkNotLocked(sym)) && (
- !sym.isAliasType && !sym.isAbstractType ||
- checkNonCyclic(pos, pre.memberInfo(sym).subst(sym.typeParams, args), sym)
+ !sym.isTypeMember ||
+ checkNonCyclic(pos, appliedType(pre.memberInfo(sym), args), sym) // @M! info for a type ref to a type parameter now returns a polytype
+ // @M was: checkNonCyclic(pos, pre.memberInfo(sym).subst(sym.typeParams, args), sym)
)
case SingleType(pre, sym) =>
checkNotLocked(sym)
@@ -524,7 +525,8 @@ trait Typers requires Analyzer {
* unapply or unapplySeq method.
*
* (6) Convert all other types to TypeTree nodes.
- * (7) When in TYPEmode nut not FUNmode, check that types are fully parameterized
+ * (7) When in TYPEmode but not FUNmode, check that types are fully parameterized
+ * (7.1) @M! when in POLYmode | TAPPmode, check that types have the expected kind
* (8) When in both EXPRmode and FUNmode, add apply method calls to values of object type.
* (9) If there are undetermined type variables and not POLYmode, infer expression instance
* Then, if tree's type is not a subtype of expected type, try the following adaptations:
@@ -584,8 +586,16 @@ trait Typers requires Analyzer {
if (tree.isType) {
if ((mode & FUNmode) != 0) {
tree
- } else if (tree.hasSymbol && !tree.symbol.typeParams.isEmpty) { // (7)
+ } else if (tree.hasSymbol && !tree.symbol.typeParams.isEmpty && (mode & (POLYmode | TAPPmode)) == 0) { // (7)
+ // @M higher-kinded types are allowed in (POLYmode | TAPPmode) -- see (7.1)
errorTree(tree, tree.symbol+" takes type parameters")
+ tree setType tree.tpe
+ } else if (tree.hasSymbol && ((mode & (POLYmode | TAPPmode)) == (POLYmode | TAPPmode)) && // (7.1) @M: check kind-arity (full checks are done in checkKindBounds in Infer)
+ tree.symbol.typeParams.length != pt.typeParams.length &&
+ !(tree.symbol==AnyClass || tree.symbol==AllClass || pt == WildcardType )) { //@M Any and Nothing are kind-polymorphic -- WildcardType is only used when typing type arguments to an overloaded method, before the overload is resolved
+ errorTree(tree, tree.symbol+" takes "+reporter.countElementsAsString(tree.symbol.typeParams.length, "type parameter")+
+ ", expected: "+reporter.countAsString(pt.typeParams.length))
+ tree setType tree.tpe
} else tree match { // (6)
case TypeTree() => tree
case _ => TypeTree(tree.tpe) setOriginal(tree)
@@ -648,7 +658,7 @@ trait Typers requires Analyzer {
if (tree1.tpe <:< pt) adapt(tree1, mode, pt)
else {
if ((mode & (EXPRmode | FUNmode)) == EXPRmode) {
- pt match {
+ pt.normalize match {
case TypeRef(_, sym, _) =>
// note: was if (pt.symbol == UnitClass) but this leads to a potentially
// infinite expansion if pt is constant type ()
@@ -824,7 +834,7 @@ trait Typers requires Analyzer {
else
psym addChild context.owner
}
- if (!(selfType <:< parent.tpe.typeOfThis) && !phase.erasedTypes) {
+ if (!(selfType <:< parent.tpe.typeOfThis) && !phase.erasedTypes) { //@M .typeOfThis seems necessary
//Console.println(context.owner);//DEBUG
//Console.println(context.owner.unsafeTypeParams);//DEBUG
//Console.println(List.fromArray(context.owner.info.closure));//DEBUG
@@ -848,7 +858,7 @@ trait Typers requires Analyzer {
if (classinfo.expansiveRefs(tparam) contains tparam) {
error(tparam.pos, "class graph is not finitary because type parameter "+tparam.name+" is expansively recursive")
val newinfo = ClassInfoType(
- classinfo.parents map (.subst(List(tparam), List(AnyRefClass.tpe))),
+ classinfo.parents map (.instantiateTypeParams(List(tparam), List(AnyRefClass.tpe))),
classinfo.decls,
clazz)
clazz.setInfo {
@@ -1137,13 +1147,15 @@ trait Typers requires Analyzer {
}
def typedAbsTypeDef(tdef: AbsTypeDef): AbsTypeDef = {
+ reenterTypeParams(tdef.tparams) // @M!
+ val tparams1 = List.mapConserve(tdef.tparams)(typedAbsTypeDef) // @M!
val lo1 = checkNoEscaping.privates(tdef.symbol, typedType(tdef.lo))
val hi1 = checkNoEscaping.privates(tdef.symbol, typedType(tdef.hi))
checkNonCyclic(tdef.symbol)
if (!(lo1.tpe <:< hi1.tpe))
error(tdef.pos,
"lower bound "+lo1.tpe+" does not conform to upper bound "+hi1.tpe)
- copy.AbsTypeDef(tdef, tdef.mods, tdef.name, lo1, hi1) setType NoType
+ copy.AbsTypeDef(tdef, tdef.mods, tdef.name, tparams1, lo1, hi1) setType NoType
}
def typedAliasTypeDef(tdef: AliasTypeDef): AliasTypeDef = {
@@ -1231,7 +1243,7 @@ trait Typers requires Analyzer {
body1 =
typed {
atPos(body1.pos) {
- TypeApply(Select(body1, Any_asInstanceOf), List(TypeTree(pt)))
+ TypeApply(Select(body1, Any_asInstanceOf), List(TypeTree(pt))) // @M no need for pt.normalize here, is done in erasure
}
}
}
@@ -1503,12 +1515,12 @@ trait Typers requires Analyzer {
val strictTargs = List.map2(lenientTargs, tparams)((targ, tparam) =>
if (targ == WildcardType) tparam.tpe else targ)
def typedArgToPoly(arg: Tree, formal: Type): Tree = {
- val lenientPt = formal.subst(tparams, lenientTargs)
+ val lenientPt = formal.instantiateTypeParams(tparams, lenientTargs)
val arg1 = typedArg(arg, mode, POLYmode, lenientPt)
val argtparams = context.undetparams
context.undetparams = List()
if (!argtparams.isEmpty) {
- val strictPt = formal.subst(tparams, strictTargs)
+ val strictPt = formal.instantiateTypeParams(tparams, strictTargs)
inferArgumentInstance(arg1, argtparams, strictPt, lenientPt)
}
arg1
@@ -1651,10 +1663,24 @@ trait Typers requires Analyzer {
//Console.println("typed1("+tree.getClass()+","+Integer.toHexString(mode)+","+pt+")")
def ptOrLub(tps: List[Type]) = if (isFullyDefined(pt)) pt else lub(tps)
+ //@M! get the type of the qualifier in a Select tree, otherwise: NoType
+ def prefixType(fun: Tree): Type = fun match {
+ case Select(qualifier, _) => qualifier.tpe
+// case Ident(name) => ??
+ case _ => NoType
+ }
+
def typedTypeApply(fun: Tree, args: List[Tree]): Tree = fun.tpe match {
case OverloadedType(pre, alts) =>
inferPolyAlternatives(fun, args map (.tpe))
- typedTypeApply(fun, args)
+ val tparams = fun.symbol.typeParams
+ assert(args.length == tparams.length) //@M: in case TypeApply we can't check the kind-arities
+ // of the type arguments as we don't know which alternative to choose... here we do
+ val args1 = map2Conserve(args, tparams) {
+ //@M! the polytype denotes the expected kind
+ (arg, tparam) => typedHigherKindedType(arg, makePolyType(tparam.typeParams, AnyClass.tpe))
+ }
+ typedTypeApply(fun, args1)
case PolyType(tparams, restpe) if (tparams.length != 0) =>
if (tparams.length == args.length) {
val targs = args map (.tpe)
@@ -1663,8 +1689,14 @@ trait Typers requires Analyzer {
if (!targs.head.symbol.isClass || targs.head.symbol.isRefinementClass)
error(args.head.pos, "class type required");
Literal(Constant(targs.head)) setPos tree.pos setType ClassClass.tpe
- } else
- copy.TypeApply(tree, fun, args) setType restpe.subst(tparams, targs)
+ } else {
+ val resultpe0 = restpe.instantiateTypeParams(tparams, targs)
+ //@M TODO -- probably ok
+ //@M example why asSeenFrom is necessary: class Foo[a] { def foo[m[x]]: m[a] } (new Foo[Int]).foo[List] : List[Int]
+ //@M however, asSeenFrom widens a singleton type, thus cannot use it for those types
+ val resultpe = if(resultpe0.isInstanceOf[SingletonType]) resultpe0 else resultpe0.asSeenFrom(prefixType(fun), fun.symbol.owner)
+ copy.TypeApply(tree, fun, args) setType resultpe
+ }
} else {
errorTree(tree, "wrong number of type parameters for "+treeSymTypeMsg(fun))
}
@@ -1867,7 +1899,7 @@ trait Typers requires Analyzer {
var qual: Tree = EmptyTree // the qualififier tree if transformed tree is a select
// if we are in a constructor of a pattern, ignore all methods
// which are not case factories (note if we don't do that
- // case x :: xs in class List would return the :: method.
+ // case x :: xs in class List would return the :: method).
def qualifies(sym: Symbol): boolean =
sym.exists &&
((mode & PATTERNmode | FUNmode) != (PATTERNmode | FUNmode) ||
@@ -1982,6 +2014,9 @@ trait Typers requires Analyzer {
}
}
+ // @M: copied from Namers
+ def makePolyType(tparams: List[Symbol], tpe: Type) = if (tparams.isEmpty) tpe else PolyType(tparams, tpe)
+
// begin typed1
val sym: Symbol = tree.symbol
if (sym ne null) sym.initialize
@@ -2004,7 +2039,7 @@ trait Typers requires Analyzer {
case ddef @ DefDef(_, _, _, _, _, _) =>
newTyper(makeNewScope(context, tree, sym)).typedDefDef(ddef)
- case tdef @ AbsTypeDef(_, _, _, _) =>
+ case tdef @ AbsTypeDef(_, _, _, _, _) =>
newTyper(makeNewScope(context, tree, sym)).typedAbsTypeDef(tdef)
case tdef @ AliasTypeDef(_, _, _, _) =>
@@ -2263,9 +2298,39 @@ trait Typers requires Analyzer {
copy.Typed(tree, expr1, tpt1) setType owntype
case TypeApply(fun, args) =>
- val args1 = List.mapConserve(args)(typedType)
- // do args first in order to maintain conext.undetparams on the function side.
- typedTypeApply(typed(fun, funMode(mode) | TAPPmode, WildcardType), args1)
+ // @M: kind-arity checking is done here and in adapt, full kind-checking is in checkKindBounds (in Infer)
+ //@M! we must type fun in order to type the args, as that requires the kinds of fun's type parameters.
+ // However, args should apparently be done first, to save context.undetparams. Unfortunately, the args
+ // *really* have to be typed *after* fun. We escape from this classic Catch-22 by simply saving&restoring undetparams.
+
+ // @M TODO: the compiler still bootstraps&all tests pass when this is commented out..
+ //val undets = context.undetparams
+
+ // @M: fun is typed in TAPPmode because it is being applied to its actual type parameters
+ val fun1 = typed(fun, funMode(mode) | TAPPmode, WildcardType)
+ val tparams = fun1.symbol.typeParams
+
+ //@M TODO: val undets_fun = context.undetparams ?
+ // "do args first" (by restoring the context.undetparams) in order to maintain context.undetparams on the function side.
+
+ // @M TODO: the compiler still bootstraps when this is commented out.. TODO: run tests
+ //context.undetparams = undets
+
+ // @M maybe the well-kindedness check should be done when checking the type arguments conform to the type parameters' bounds?
+ val args1 = if(args.length == tparams.length) map2Conserve(args, tparams) {
+ //@M! the polytype denotes the expected kind
+ (arg, tparam) => typedHigherKindedType(arg, makePolyType(tparam.typeParams, AnyClass.tpe))
+ } else {
+ assert(fun1.symbol.info.isInstanceOf[OverloadedType])
+ // @M this branch is hit for an overloaded polymorphic type.
+ // Until the right alternative is known, be very liberal,
+ // typedTypeApply will find the right alternative and then do the same check as
+ // in the then-branch above. (see pos/tcpoly_overloaded.scala)
+ List.mapConserve(args)(typedHigherKindedType)
+ }
+
+ //@M TODO: context.undetparams = undets_fun ?
+ typedTypeApply(fun1, args1)
case Apply(Block(stats, expr), args) =>
typed1(atPos(tree.pos)(Block(stats, Apply(expr, args))), mode, pt)
@@ -2408,13 +2473,18 @@ trait Typers requires Analyzer {
case AppliedTypeTree(tpt, args) =>
val tpt1 = typed1(tpt, mode | FUNmode | TAPPmode, WildcardType)
val tparams = tpt1.symbol.typeParams
- val args1 = List.mapConserve(args)(typedType)
+
if (tpt1.tpe.isError) {
setError(tree)
- } else if (tparams.length == args1.length) {
+ } else if (tparams.length == args.length) {
+ // @M: kind-arity checking is done here and in adapt, full kind-checking is in checkKindBounds (in Infer)
+ val args1 = map2Conserve(args, tparams) {
+ (arg, tparam) => typedHigherKindedType(arg, makePolyType(tparam.typeParams, AnyClass.tpe)) //@M! the polytype denotes the expected kind
+ }
val argtypes = args1 map (.tpe)
- val owntype = if (tpt1.symbol.isClass) appliedType(tpt1.tpe, argtypes)
- else tpt1.tpe.subst(tparams, argtypes)
+ val owntype = if (tpt1.symbol.isClass || tpt1.symbol.isTypeMember) // @M! added the latter condition
+ appliedType(tpt1.tpe, argtypes)
+ else tpt1.tpe.instantiateTypeParams(tparams, argtypes)
List.map2(args, tparams) { (arg, tparam) => arg match {
// note: can't use args1 in selector, because Bind's got replaced
case Bind(_, _) =>
@@ -2476,8 +2546,8 @@ trait Typers requires Analyzer {
reportTypeError(tree.pos, ex)
setError(tree)
case ex: Throwable =>
- if (settings.debug.value)
- Console.println("exception when typing "+tree+", pt = "+pt)
+// if (settings.debug.value) // @M causes cyclic reference error
+// Console.println("exception when typing "+tree+", pt = "+pt)
if ((context ne null) && (context.unit ne null) &&
(context.unit.source ne null) && (tree ne null))
logError("AT: " + context.unit.source.dbg(tree.pos), ex);
@@ -2530,12 +2600,20 @@ trait Typers requires Analyzer {
def typedType(tree: Tree): Tree =
withNoGlobalVariance{ typed(tree, TYPEmode, WildcardType) }
+ /** Types a higher-kinded type tree -- pt denotes the expected kind*/
+ def typedHigherKindedType(tree: Tree, pt: Type): Tree =
+ if(pt.typeParams.isEmpty) typedType(tree) // kind is known and it's *
+ else withNoGlobalVariance{ typed(tree, POLYmode | TAPPmode, pt) }
+
+ def typedHigherKindedType(tree: Tree): Tree =
+ withNoGlobalVariance{ typed(tree, POLYmode | TAPPmode, WildcardType) }
+
/** Types a type constructor tree used in a new or supertype */
def typedTypeConstructor(tree: Tree): Tree = {
val result = withNoGlobalVariance{ typed(tree, TYPEmode | FUNmode, WildcardType) }
if (!phase.erasedTypes && result.tpe.isInstanceOf[TypeRef] && !result.tpe.prefix.isStable)
error(tree.pos, result.tpe.prefix+" is not a legal prefix for a constructor")
- result
+ result setType(result.tpe.normalize) // @MAT remove aliases when instantiating
}
def computeType(tree: Tree, pt: Type): Type = {
@@ -2558,7 +2636,7 @@ trait Typers requires Analyzer {
/* -- Views --------------------------------------------------------------- */
private def tparamsToWildcards(tp: Type, tparams: List[Symbol]) =
- tp.subst(tparams, tparams map (t => WildcardType))
+ tp.instantiateTypeParams(tparams, tparams map (t => WildcardType))
private def depoly(tp: Type): Type = tp match {
case PolyType(tparams, restpe) => tparamsToWildcards(restpe, tparams)