diff options
author | Martin Odersky <odersky@gmail.com> | 2013-09-27 22:10:45 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2013-09-28 11:43:43 +0200 |
commit | 0c582b883971fd89476244aa6905be95da7e79d0 (patch) | |
tree | 079efc09d1e5b53b1e258b565dbb15c8b14954f7 | |
parent | fcb68309c2760a6797b0a9ec23722808060e9aa1 (diff) | |
download | dotty-0c582b883971fd89476244aa6905be95da7e79d0.tar.gz dotty-0c582b883971fd89476244aa6905be95da7e79d0.tar.bz2 dotty-0c582b883971fd89476244aa6905be95da7e79d0.zip |
Several bug fixes to typer and classfile reader.
In particular, changed internal representation of Java constructors and
changed treatment of parent constructors in templates.
-rw-r--r-- | src/dotty/tools/dotc/ast/CheckTrees.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/Desugar.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/TreeInfo.scala | 13 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/TypedTrees.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Denotations.scala | 6 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Flags.scala | 5 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/TypeComparer.scala | 10 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 9 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/pickling/ClassfileParser.scala | 39 | ||||
-rw-r--r-- | src/dotty/tools/dotc/parsing/Parsers.scala | 7 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Applications.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Inferencing.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Namer.scala | 10 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 6 | ||||
-rw-r--r-- | tests/pos/inferred.scala | 24 |
15 files changed, 105 insertions, 40 deletions
diff --git a/src/dotty/tools/dotc/ast/CheckTrees.scala b/src/dotty/tools/dotc/ast/CheckTrees.scala index 92a069a76..b99548162 100644 --- a/src/dotty/tools/dotc/ast/CheckTrees.scala +++ b/src/dotty/tools/dotc/ast/CheckTrees.scala @@ -206,7 +206,7 @@ object CheckTrees { check(args.head.isInstanceOf[SeqLiteral]) case nme.unapply => val rtp = funtpe.resultType - val rsym = rtp.dealias.typeSymbol + val rsym = rtp.dealiasedTypeSymbol if (rsym == defn.BooleanClass) check(args.isEmpty) else { @@ -216,7 +216,7 @@ object CheckTrees { optionArg.typeArgs match { case Nil => optionArg :: Nil - case tupleArgs if defn.TupleClasses contains optionArg.dealias.typeSymbol => + case tupleArgs if defn.TupleClasses contains optionArg.dealiasedTypeSymbol => tupleArgs } case _ => diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala index f58df1739..31154b2ef 100644 --- a/src/dotty/tools/dotc/ast/Desugar.scala +++ b/src/dotty/tools/dotc/ast/Desugar.scala @@ -105,11 +105,11 @@ object desugar { case _ => rhs } - if (mods is PrivateLocalParamAccessor) { + if (mods is PrivateLocalParam) { val tparam = cpy.TypeDef(tdef, mods &~ PrivateLocal | ExpandedName, name.expandedName(ctx.owner), rhs1, tdef.tparams) val alias = cpy.TypeDef(tdef, - Modifiers(PrivateLocal | Synthetic), name, refOfDef(tparam)) + Modifiers(PrivateLocalParamAccessor | Synthetic), name, refOfDef(tparam)) Thicket(tparam, alias) } else cpy.TypeDef(tdef, mods, name, rhs1) diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala index 665fbec89..e8303e6b8 100644 --- a/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -67,13 +67,20 @@ trait TreeInfo[T >: Untyped] { self: Trees.Instance[T] => * <init>(x$2, x$1) * } */ - def methPart(tree: Tree): Tree = tree match { - case Apply(fn, _) => methPart(fn) + def methPart(tree: Tree): Tree = stripApply(tree) match { case TypeApply(fn, _) => methPart(fn) - case AppliedTypeTree(fn, _) => methPart(fn) + case AppliedTypeTree(fn, _) => methPart(fn) // !!! should not be needed case Block(stats, expr) => methPart(expr) case _ => tree } + + /** If this is an application, its function part, stripping all + * Apply nodes (but leaving TypeApply nodes in). Otherwise the tree itself. + */ + def stripApply(tree: Tree): Tree = tree match { + case Apply(fn, _) => stripApply(fn) + case _ => tree + } /** The number of arguments in an application */ def numArgs(tree: Tree): Int = tree match { diff --git a/src/dotty/tools/dotc/ast/TypedTrees.scala b/src/dotty/tools/dotc/ast/TypedTrees.scala index a126108aa..79e54fccb 100644 --- a/src/dotty/tools/dotc/ast/TypedTrees.scala +++ b/src/dotty/tools/dotc/ast/TypedTrees.scala @@ -255,9 +255,9 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { val selfType = if (cls.classInfo.selfInfo ne NoType) ValDef(ctx.newSelfSym(cls)) else EmptyValDef - def isOwnTypeParamAccessor(stat: Tree) = + def isOwnTypeParam(stat: Tree) = (stat.symbol is TypeParam) && stat.symbol.owner == cls - val bodyTypeParams = body filter isOwnTypeParamAccessor map (_.symbol) + val bodyTypeParams = body filter isOwnTypeParam map (_.symbol) val newTypeParams = for (tparam <- cls.typeParams if !(bodyTypeParams contains tparam)) yield TypeDef(tparam) diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala index 89c0b3861..74b669a77 100644 --- a/src/dotty/tools/dotc/core/Denotations.scala +++ b/src/dotty/tools/dotc/core/Denotations.scala @@ -397,13 +397,13 @@ object Denotations { def orElse(that: => SingleDenotation) = if (this.exists) this else that def altsWith(p: Symbol => Boolean): List[SingleDenotation] = - if (p(symbol)) this :: Nil else Nil + if (exists && p(symbol)) this :: Nil else Nil def suchThat(p: Symbol => Boolean): SingleDenotation = - if (p(symbol)) this else NoDenotation + if (exists && p(symbol)) this else NoDenotation def hasAltWith(p: SingleDenotation => Boolean): Boolean = - p(this) + exists && p(this) def accessibleFrom(pre: Type, superAccess: Boolean)(implicit ctx: Context): Denotation = if (symbol isAccessibleFrom (pre, superAccess)) this else NoDenotation diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala index 229d71568..0c433ecc5 100644 --- a/src/dotty/tools/dotc/core/Flags.scala +++ b/src/dotty/tools/dotc/core/Flags.scala @@ -235,6 +235,8 @@ object Flags { * or an accessor of such a field. */ final val ParamAccessor = commonFlag(14, "<paramaccessor>") + final val TermParamAccessor = ParamAccessor.toTermFlags + final val TypeParamAccessor = ParamAccessor.toTypeFlags /** A value or class implementing a module */ final val Module = commonFlag(15, "module") @@ -471,6 +473,9 @@ object Flags { /** A private parameter accessor */ final val PrivateLocalParamAccessor = allOf(Private, Local, ParamAccessor) + /** A private parameter */ + final val PrivateLocalParam = allOf(Private, Local, Param) + /** A local parameter */ final val ParamAndLocal = allOf(Param, Local) diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index 588756db4..1d853c44d 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -220,10 +220,9 @@ class TypeComparer(initctx: Context) extends DotClass { case tp2: RefinedType => isSubType(tp1, tp2.parent) && ( tp2.refinedName == nme.WILDCARD - || (tp1 isRef NothingClass) - || (tp1 isRef NullClass) || tp1.member(tp2.refinedName).hasAltWith(alt => - isSubType(alt.info, tp2.refinedInfo))) + isSubType(alt.info, tp2.refinedInfo)) + || fourthTry(tp1, tp2)) case AndType(tp21, tp22) => isSubType(tp1, tp21) && isSubType(tp1, tp22) case OrType(tp21, tp22) => @@ -280,7 +279,7 @@ class TypeComparer(initctx: Context) extends DotClass { def fourthTry(tp1: Type, tp2: Type): Boolean = tp1 match { case tp1: TypeRef => ((tp1.symbol eq NothingClass) - || (tp1.symbol eq NullClass) && tp2.dealias.typeSymbol.isNonValueClass + || (tp1.symbol eq NullClass) && tp2.dealiasedTypeSymbol.isNonValueClass || (tp1.info match { case TypeBounds(lo1, hi1) => isSubType(hi1, tp2) || @@ -289,6 +288,8 @@ class TypeComparer(initctx: Context) extends DotClass { })) case tp1: SingletonType => isSubType(tp1.underlying, tp2) + case tp1: ExprType => + isSubType(tp1.underlying, tp2) case tp1: RefinedType => isSubType(tp1.parent, tp2) case AndType(tp11, tp12) => @@ -544,7 +545,6 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) { private val b = new StringBuilder def traceIndented[T](str: String)(op: => T): T = { - assert(str != "<notype> <:< Int") indent += 2 b append "\n" append (" " * indent) append "==> " append str val res = op diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index ee76f0dc7..59ac01819 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -214,6 +214,15 @@ object Types { case _ => NoSymbol } + /** The type symbol associated with the type, skipping alises */ + final def dealiasedTypeSymbol(implicit ctx: Context): Symbol = this match { + case tp: TermRef => NoSymbol + case tp: ClassInfo => tp.cls + case ThisType(cls) => cls + case tp: TypeProxy => tp.underlying.dealiasedTypeSymbol + case _ => NoSymbol + } + /** The least class or trait of which this type is a subtype, or * NoSymbol if none exists (either because this type is not a * value type, or because superclasses are ambiguous). diff --git a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala index f640c3d67..b65fc55bb 100644 --- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala +++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala @@ -164,6 +164,7 @@ class ClassfileParser( } val memberCompleter = new LazyType { + def complete(denot: SymDenotation): Unit = { val oldbp = in.bp try { @@ -172,19 +173,35 @@ class ClassfileParser( val jflags = in.nextChar val isEnum = (jflags & JAVA_ACC_ENUM) != 0 val name = pool.getName(in.nextChar) - val info = pool.getType(in.nextChar) + val isConstructor = name eq nme.CONSTRUCTOR + + /** Strip leading outer param from constructor. + * Todo: Also strip trailing access tag for private inner constructors? + */ + def stripOuterParamFromConstructor() = innerClasses.get(currentClassName) match { + case Some(entry) if !isStatic(entry.jflags) => + val mt @ MethodType(paramnames, paramtypes) = denot.info + denot.info = mt.derivedMethodType(paramnames.tail, paramtypes.tail, mt.resultType) + case _ => + } - denot.info = if (isEnum) ConstantType(Constant(sym)) else info - if (name == nme.CONSTRUCTOR) - // if this is a non-static inner class, remove the explicit outer parameter - innerClasses.get(currentClassName) match { - case Some(entry) if !isStatic(entry.jflags) => - val mt @ MethodType(paramnames, paramtypes) = info - denot.info = mt.derivedMethodType(paramnames.tail, paramtypes.tail, mt.resultType) - case _ => - } + /** Make return type of constructor be the enclosing class type, + * and make constructor type polymorphic in the type parameters of the class + */ + def normalizeConstructorInfo() = { + val mt @ MethodType(paramnames, paramtypes) = denot.info + val typeParams = classRoot.typeParams + val rt = classRoot.typeConstructor appliedTo (typeParams map (_.symRef)) + denot.info = PolyType.fromSymbols(typeParams, + mt.derivedMethodType(paramnames, paramtypes, rt)) + } + + denot.info = pool.getType(in.nextChar) + if (isEnum) denot.info = ConstantType(Constant(sym)) + if (isConstructor) stripOuterParamFromConstructor() setPrivateWithin(denot, jflags) - denot.info = depoly(parseAttributes(sym, info), denot) + denot.info = depoly(parseAttributes(sym, denot.info), denot) + if (isConstructor) normalizeConstructorInfo() if ((denot is Flags.Method) && (jflags & JAVA_ACC_VARARGS) != 0) denot.info = arrayToRepeated(denot.info) diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala index b1d314d7e..57356f305 100644 --- a/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1401,7 +1401,12 @@ object Parsers { } /** Wrap annotation or constructor in New(...).<init> */ - def wrapNew(tpt: Tree) = Select(New(tpt), nme.CONSTRUCTOR) + def wrapNew(tpt: Tree) = tpt match { + case AppliedTypeTree(tpt1, targs) => + TypeApply(Select(New(tpt1), nme.CONSTRUCTOR), targs) + case _ => + Select(New(tpt), nme.CONSTRUCTOR) + } /** Adjust start of annotation or constructor to position of preceding @ or new */ def adjustStart(start: Offset)(tree: Tree): Tree = { diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index bf49091ec..673791d8d 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -475,7 +475,7 @@ trait Applications extends Compatibility { self: Typer => val qual1 = adapt(qual, new SelectionProto(name, proto)) if (qual1.tpe.isError) qual1 else { - assert(qual1 ne qual) + assert(qual1 ne qual, s"$qual1 : ${qual1.tpe}") typedApply( cpy.Apply(tree, cpy.Select(fun1, untpd.TypedSplice(qual1), name), diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala index 2137981e7..c514699a3 100644 --- a/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/src/dotty/tools/dotc/typer/Inferencing.scala @@ -153,7 +153,7 @@ object Inferencing { case tp: TypeRef if tp.symbol.isClass => checkStable(tp.prefix, pos) tp.symbol.asClass - case _: RefinedType | _: TypeVar | _: AnnotatedType => + case /* _: RefinedType |*/ _: TypeVar | _: AnnotatedType => checkClassTypeWithStablePrefix(tp.asInstanceOf[TypeProxy].underlying, pos) case _ => ctx.error(i"$tp is not a class type", pos) diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala index a803903bb..e9eb7df0b 100644 --- a/src/dotty/tools/dotc/typer/Namer.scala +++ b/src/dotty/tools/dotc/typer/Namer.scala @@ -13,6 +13,7 @@ import util.SourcePosition import collection.mutable import annotation.tailrec import ErrorReporting._ +import tpd.ListOfTreeDecorator import language.implicitConversions trait NamerContextOps { this: Context => @@ -296,8 +297,13 @@ class Namer { typer: Typer => def classDefSig(cdef: TypeDef, cls: ClassSymbol)(implicit ctx: Context): Type = { //todo: normalize parents, so that all mixins extend superclass def parentType(constr: untpd.Tree): Type = { - val Trees.Select(Trees.New(tpt), _) = methPart(constr) - val ptype = typedAheadType(tpt).tpe + val (core, targs) = stripApply(constr) match { + case TypeApply(core, targs) => (core, targs) + case core => (core, Nil) + } + val Select(New(tpt), _) = core + val targs1 = targs map (typedAheadType(_)) + val ptype = typedAheadType(tpt).tpe appliedTo targs1.tpes if (ptype.uninstantiatedTypeParams.isEmpty) ptype else typedAheadExpr(constr).tpe } diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 0c33aa026..21ebc196a 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -120,7 +120,11 @@ class Typer extends Namer with Applications with Implicits { alts foreach (_.isAccessibleFrom(pre, superAccess, whyNot)) ctx.error(i"$what cannot be accessed in $where.$whyNot") ErrorType - } else tpe withDenot d + } + else if (d.symbol is TypeParamAccessor) // always dereference type param accessors + checkAccessible(d.info.bounds.hi, superAccess, pos) + else + tpe withDenot d case _ => tpe } diff --git a/tests/pos/inferred.scala b/tests/pos/inferred.scala index 29e1345c1..432cd8acd 100644 --- a/tests/pos/inferred.scala +++ b/tests/pos/inferred.scala @@ -1,14 +1,26 @@ class List[+T] { - def prepend [U >: T] (x: U): List[U] = null//new Cons(x, this) + def isEmpty: Boolean + def head: T + def tail: List[T] - def map[U](f: T => U): List[U] = null + def prepend [U >: T] (x: U): List[U] = new Cons(x, this) + + def map[U](f: T => U): List[U] = if (isEmpty) Nil else tail.map(f).prepend(f(head)) } -object Nil extends List[Nothing] +object Nil extends List[Nothing] { + def isEmpty = true + def head = throw new Error() + def tail = ??? +} -//class Cons[T](hd: T, tl: List[T]) extends List[T] +class Cons[T](hd: T, tl: List[T]) extends List[T] { + def isEmpty = false + def head = hd + def tail = tl +} object Inferred { @@ -35,7 +47,7 @@ object Inferred { val ss3 = "abc" :: n2 - def closure = ((x: Int) => x) + def cl = ((x: Int) => x + 1) - val ints2 = ints map closure + val ints2 = ints map (_ + 1) }
\ No newline at end of file |