diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala index 0c741a652c58..ea9e7566a23d 100644 --- a/src/dotty/tools/dotc/ast/Desugar.scala +++ b/src/dotty/tools/dotc/ast/Desugar.scala @@ -8,6 +8,7 @@ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._ import Decorators._ import language.higherKinds import collection.mutable.ListBuffer +import config.Printers._ import typer.ErrorReporting.InfoString import typer.Mode @@ -21,6 +22,67 @@ object desugar { /** Info of a variable in a pattern: The named tree and its type */ private type VarInfo = (NameTree, Tree) +// ----- DerivedTypeTrees ----------------------------------- + + class SetterParamTree extends DerivedTypeTree { + def derivedType(sym: Symbol)(implicit ctx: Context) = sym.info.resultType + } + + class TypeRefTree extends DerivedTypeTree { + def derivedType(sym: Symbol)(implicit ctx: Context) = sym.typeRef + } + + class DerivedFromParamTree extends DerivedTypeTree { + + /** Make sure that for all enclosing module classes their companion lasses + * are completed. Reason: We need the constructor of such companion classes to + * be completed so that OriginalSymbol attachments are pushed to DerivedTypeTrees + * in appy/unapply methods. + */ + override def ensureCompletions(implicit ctx: Context) = + if (!(ctx.owner is Package)) + if (ctx.owner is ModuleClass) ctx.owner.linkedClass.ensureCompleted() + else ensureCompletions(ctx.outer) + + /** Return info of original symbol, where all references to siblings of the + * original symbol (i.e. sibling and original symbol have the same owner) + * are rewired to same-named parameters or accessors in the scope enclosing + * the current scope. The current scope is the scope owned by the defined symbol + * itself, that's why we have to look one scope further out. If the resulting + * type is an alias type, dealias it. This is necessary because the + * accessor of a type parameter is a private type alias that cannot be accessed + * from subclasses. + */ + def derivedType(sym: Symbol)(implicit ctx: Context) = { + val relocate = new TypeMap { + val originalOwner = sym.owner + def apply(tp: Type) = tp match { + case tp: NamedType if tp.symbol.owner eq originalOwner => + val defctx = ctx.outersIterator.dropWhile(_.scope eq ctx.scope).next + var local = defctx.denotNamed(tp.name).suchThat(_ is ParamOrAccessor).symbol + typr.println(s"rewiring ${tp.symbol} from ${originalOwner.showLocated} to ${local.showLocated}, current owner = ${ctx.owner.showLocated}") + if (local.exists) (defctx.owner.thisType select local).dealias + else throw new Error(s"no matching symbol for ${sym.showLocated} in ${defctx.owner} / ${defctx.effectiveScope}") + case _ => + mapOver(tp) + } + } + relocate(sym.info) + } + } + + /** A type definition copied from `tdef` with a rhs typetree derived from it */ + def derivedTypeParam(tdef: TypeDef) = + cpy.TypeDef(tdef, tdef.mods, tdef.name, + new DerivedFromParamTree() withPos tdef.rhs.pos watching tdef, tdef.tparams) // todo: copy type params + + /** A value definition copied from `vdef` with a tpt typetree derived from it */ + def derivedTermParam(vdef: ValDef) = + cpy.ValDef(vdef, vdef.mods, vdef.name, + new DerivedFromParamTree() withPos vdef.tpt.pos watching vdef, vdef.rhs) + +// ----- Desugar methods ------------------------------------------------- + /** var x: Int = expr * ==> * def x: Int = expr @@ -35,7 +97,7 @@ object desugar { // val getter = ValDef(mods, name, tpt, rhs) withPos vdef.pos ? // right now vdef maps via expandedTree to a thicket which concerns itself. // I don't see a problem with that but if there is one we can avoid it by making a copy here. - val setterParam = makeSyntheticParameter(tpt = TypeTree()) + val setterParam = makeSyntheticParameter(tpt = (new SetterParamTree).watching(vdef)) val setterRhs = if (vdef.rhs.isEmpty) EmptyTree else unitLiteral val setter = cpy.DefDef(vdef, mods | Accessor, name.setterName, Nil, (setterParam :: Nil) :: Nil, @@ -151,6 +213,9 @@ object desugar { private def toDefParam(tparam: TypeDef) = cpy.TypeDef(tparam, Modifiers(Param), tparam.name, tparam.rhs, tparam.tparams) + private def toDefParam(vparam: ValDef) = + cpy.ValDef(vparam, Modifiers(Param | vparam.mods.flags & Implicit), vparam.name, vparam.tpt, vparam.rhs) + /** The expansion of a class definition. See inline comments for what is involved */ def classDef(cdef: TypeDef)(implicit ctx: Context): Tree = { val TypeDef( @@ -166,31 +231,35 @@ object desugar { // prefixed by type or val). `tparams` and `vparamss` are the type parameters that // go in `constr`, the constructor after desugaring. - val tparams = constr1.tparams map toDefParam - val vparamss = + val constrTparams = constr1.tparams map toDefParam + val constrVparamss = if (constr1.vparamss.isEmpty) { // ensure parameter list is non-empty if (mods is Case) ctx.error("case class needs to have at least one parameter list", cdef.pos) ListOfNil - } else - constr1.vparamss.nestedMap(vparam => cpy.ValDef(vparam, - Modifiers(Param | vparam.mods.flags & Implicit), vparam.name, vparam.tpt, vparam.rhs)) - + } + else constr1.vparamss.nestedMap(toDefParam) val constr = cpy.DefDef(constr1, - constr1.mods, constr1.name, tparams, vparamss, constr1.tpt, constr1.rhs) + constr1.mods, constr1.name, constrTparams, constrVparamss, constr1.tpt, constr1.rhs) + + val derivedTparams = constrTparams map derivedTypeParam + val derivedVparamss = constrVparamss nestedMap derivedTermParam + val arity = constrVparamss.head.length + + var classTycon: Tree = EmptyTree // a reference to the class type, with all parameters given. val classTypeRef/*: Tree*/ = { // -language:keepUnions difference: classTypeRef needs type annotation, otherwise // infers Ident | AppliedTypeTree, which // renders the :\ in companions below untypable. - val tycon = Ident(cdef.name) withPos cdef.pos.startPos + classTycon = (new TypeRefTree) withPos cdef.pos.startPos // watching is set at end of method val tparams = impl.constr.tparams - if (tparams.isEmpty) tycon else AppliedTypeTree(tycon, tparams map refOfDef) + if (tparams.isEmpty) classTycon else AppliedTypeTree(classTycon, tparams map refOfDef) } // new C[Ts](paramss) - lazy val creatorExpr = New(classTypeRef, vparamss nestedMap refOfDef) + lazy val creatorExpr = New(classTypeRef, constrVparamss nestedMap refOfDef) // Methods to add to a case class C[..](p1: T1, ..., pN: Tn)(moreParams) // def isDefined = true @@ -201,23 +270,23 @@ object desugar { // def copy(p1: T1 = p1, ..., pN: TN = pN)(moreParams) = new C[...](p1, ..., pN)(moreParams) val caseClassMeths = if (mods is Case) { - val caseParams = vparamss.head.toArray def syntheticProperty(name: TermName, rhs: Tree) = DefDef(synthetic, name, Nil, Nil, TypeTree(), rhs) val isDefinedMeth = syntheticProperty(nme.isDefined, Literal(Constant(true))) - val productArityMeth = syntheticProperty(nme.productArity, Literal(Constant(caseParams.length))) + val productArityMeth = syntheticProperty(nme.productArity, Literal(Constant(arity))) def selectorName(n: Int) = - if (caseParams.length == 1) nme.get else nme.selectorName(n) - val productElemMeths = for (i <- 0 until caseParams.length) yield + if (arity == 1) nme.get else nme.selectorName(n) + val caseParams = constrVparamss.head.toArray + val productElemMeths = for (i <- 0 until arity) yield syntheticProperty(selectorName(i), Select(This(EmptyTypeName), caseParams(i).name)) val copyMeths = if (mods is Abstract) Nil else { - val copyFirstParams = vparamss.head.map(vparam => + val copyFirstParams = derivedVparamss.head.map(vparam => cpy.ValDef(vparam, vparam.mods, vparam.name, vparam.tpt, refOfDef(vparam))) - val copyRestParamss = vparamss.tail.nestedMap(vparam => + val copyRestParamss = derivedVparamss.tail.nestedMap(vparam => cpy.ValDef(vparam, vparam.mods, vparam.name, vparam.tpt, EmptyTree)) - DefDef(synthetic, nme.copy, tparams, copyFirstParams :: copyRestParamss, TypeTree(), creatorExpr) :: Nil + DefDef(synthetic, nme.copy, derivedTparams, copyFirstParams :: copyRestParamss, TypeTree(), creatorExpr) :: Nil } copyMeths ::: isDefinedMeth :: productArityMeth :: productElemMeths.toList } @@ -226,15 +295,14 @@ object desugar { def anyRef = ref(defn.AnyRefAlias.typeRef) def productConstr(n: Int) = { val tycon = ref(defn.ProductNClass(n).typeRef) - val targs = vparamss.head map (_.tpt) + val targs = constrVparamss.head map (_.tpt) AppliedTypeTree(tycon, targs) } // Case classes get a ProductN parent var parents1 = parents - val n = vparamss.head.length - if ((mods is Case) && 2 <= n && n <= Definitions.MaxTupleArity) - parents1 = parents1 :+ productConstr(n) + if ((mods is Case) && 2 <= arity && arity <= Definitions.MaxTupleArity) + parents1 = parents1 :+ productConstr(arity) // The thicket which is the desugared version of the companion object // synthetic object C extends parentTpt { defs } @@ -256,17 +324,18 @@ object desugar { val companions = if (mods is Case) { val parent = - if (tparams.nonEmpty) anyRef - else (vparamss :\ classTypeRef) ((vparams, restpe) => Function(vparams map (_.tpt), restpe)) + if (constrTparams.nonEmpty) anyRef // todo: also use anyRef if constructor has a dependent method type (or rule that out)! + else (constrVparamss :\ classTypeRef) ((vparams, restpe) => Function(vparams map (_.tpt), restpe)) val applyMeths = if (mods is Abstract) Nil - else DefDef( + else + DefDef( synthetic | (constr1.mods.flags & DefaultParameterized), nme.apply, - tparams, vparamss, TypeTree(), creatorExpr) :: Nil + derivedTparams, derivedVparamss, TypeTree(), creatorExpr) :: Nil val unapplyMeth = { val unapplyParam = makeSyntheticParameter(tpt = classTypeRef) - val unapplyRHS = if (n == 0) Literal(Constant(true)) else Ident(unapplyParam.name) - DefDef(synthetic, nme.unapply, tparams, (unapplyParam :: Nil) :: Nil, TypeTree(), unapplyRHS) + val unapplyRHS = if (arity == 0) Literal(Constant(true)) else Ident(unapplyParam.name) + DefDef(synthetic, nme.unapply, derivedTparams, (unapplyParam :: Nil) :: Nil, TypeTree(), unapplyRHS) } companionDefs(parent, applyMeths ::: unapplyMeth :: defaultGetters) } @@ -283,19 +352,40 @@ object desugar { ctx.error("implicit classes may not be toplevel", cdef.pos) if (mods is Case) ctx.error("implicit classes may not case classes", cdef.pos) + + // implicit wrapper is typechecked in same scope as constructor, so + // we can reuse the constructor parameters; no derived params are needed. DefDef(Modifiers(Synthetic | Implicit), name.toTermName, - tparams, vparamss, classTypeRef, creatorExpr) :: Nil + constrTparams, constrVparamss, classTypeRef, creatorExpr) :: Nil } else Nil - val selfType = if (self.tpt.isEmpty) classTypeRef else self.tpt - val self1 = + val self1 = { + val selfType = if (self.tpt.isEmpty) classTypeRef else self.tpt if (self.isEmpty) self else cpy.ValDef(self, self.mods | SelfName, self.name, selfType, self.rhs) + } + + val cdef1 = { + val originalTparams = constr1.tparams.toIterator + val originalVparams = constr1.vparamss.toIterator.flatten + val tparamAccessors = derivedTparams map { tdef => + cpy.TypeDef(tdef, originalTparams.next.mods, tdef.name, tdef.rhs, tdef.tparams) + } + val vparamAccessors = derivedVparamss.flatten map { vdef => + cpy.ValDef(vdef, originalVparams.next.mods, vdef.name, vdef.tpt, vdef.rhs) + } + cpy.TypeDef(cdef, mods, name, + cpy.Template(impl, constr, parents1, self1, + tparamAccessors ::: vparamAccessors ::: body ::: caseClassMeths)) + } + + // install the watch on classTycon + classTycon match { + case tycon: DerivedTypeTree => tycon.watching(cdef1) + case _ => + } - val cdef1 = cpy.TypeDef(cdef, mods, name, - cpy.Template(impl, constr, parents1, self1, - constr1.tparams ::: constr1.vparamss.flatten ::: body ::: caseClassMeths)) flatTree(cdef1 :: companions ::: implicitWrappers) } diff --git a/src/dotty/tools/dotc/ast/untpd.scala b/src/dotty/tools/dotc/ast/untpd.scala index 4e55fe868e60..44f34093235d 100644 --- a/src/dotty/tools/dotc/ast/untpd.scala +++ b/src/dotty/tools/dotc/ast/untpd.scala @@ -6,12 +6,13 @@ import core._ import util.Positions._, Types._, Contexts._, Constants._, Names._, NameOps._, Flags._ import Denotations._, SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._ import Decorators._ +import util.Attachment import language.higherKinds import collection.mutable.ListBuffer object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { -// ----- Tree cases that exist in untyped form only ------------------ + // ----- Tree cases that exist in untyped form only ------------------ trait OpTree extends Tree { def op: Name @@ -61,6 +62,47 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { override def withName(name: Name)(implicit ctx: Context) = cpy.PolyTypeDef(this, mods, name.toTypeName, tparams, rhs) } + // ----- TypeTrees that refer to other tree's symbols ------------------- + + /** A type tree that gets its type from some other tree's symbol. Enters the + * type tree in the References attachment of the `from` tree as a side effect. + */ + abstract class DerivedTypeTree extends TypeTree(EmptyTree) { + + private var myWatched: Tree = EmptyTree + + /** The watched tree; used only for printing */ + def watched: Tree = myWatched + + /** Install the derived type tree as a dependency on `original` */ + def watching(original: DefTree): this.type = { + myWatched = original + val existing = original.attachmentOrElse(References, Nil) + original.putAttachment(References, this :: existing) + this + } + + /** A hook to ensure that all necessary symbols are completed so that + * OriginalSymbol attachments are propagated to this tree + */ + def ensureCompletions(implicit ctx: Context): Unit = () + + /** The method that computes the type of this tree */ + def derivedType(originalSym: Symbol)(implicit ctx: Context): Type + } + + /** Attachment key containing TypeTrees whose type is computed + * from the symbol in this type. These type trees have marker trees + * TypeRefOfSym or InfoOfSym as their originals. + */ + val References = new Attachment.Key[List[Tree]] + + /** Attachment key for TypeTrees marked with TypeRefOfSym or InfoOfSym + * which contains the symbol of the original tree from which this + * TypeTree is derived. + */ + val OriginalSymbol = new Attachment.Key[Symbol] + // ------ Creation methods for untyped only ----------------- def Ident(name: Name): Ident = new Ident(name) diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 0d84a9e61628..1a65b29789e5 100644 --- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -241,6 +241,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { } case SeqLiteral(elems) => "[" ~ toTextGlobal(elems, ",") ~ "]" + case tpt: untpd.DerivedTypeTree => + "" case TypeTree(orig) => if (tree.hasType) toText(tree.typeOpt) else toText(orig) case SingletonTypeTree(ref) => diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala index 39da1dbaeaa8..36822cb851b5 100644 --- a/src/dotty/tools/dotc/typer/Checking.scala +++ b/src/dotty/tools/dotc/typer/Checking.scala @@ -84,7 +84,8 @@ trait Checking extends NoChecking { /** Check that (return) type of implicit definition is not empty */ override def checkImplicitTptNonEmpty(defTree: untpd.ValOrDefDef)(implicit ctx: Context): Unit = defTree.tpt match { - case TypeTree(original) if original.isEmpty => + case tpt: untpd.DerivedTypeTree => + case TypeTree(untpd.EmptyTree) => val resStr = if (defTree.isInstanceOf[untpd.DefDef]) "result " else "" ctx.error(i"${resStr}type of implicit definition needs to be given explicitly", defTree.pos) case _ => diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala index c318ddf3699c..7885e85acdf2 100644 --- a/src/dotty/tools/dotc/typer/Namer.scala +++ b/src/dotty/tools/dotc/typer/Namer.scala @@ -72,6 +72,13 @@ trait NamerContextOps { this: Context => } go(this) } + + /** Context where `sym` is defined, assuming we are in a nested context. */ + def defContext(sym: Symbol) = + outersIterator + .dropWhile(_.owner != sym) + .dropWhile(_.owner == sym) + .next } /** This class creates symbols from definitions and imports and gives them @@ -173,6 +180,11 @@ class Namer { typer: Typer => enclosingClassNamed(mods.privateWithin, mods.pos) def record(sym: Symbol): Symbol = { + val refs = tree.attachmentOrElse(References, Nil) + if (refs.nonEmpty) { + tree.removeAttachment(References) + refs foreach (_.pushAttachment(OriginalSymbol, sym)) + } tree.pushAttachment(SymOfTree, sym) sym } @@ -444,15 +456,25 @@ class Namer { typer: Typer => if (self.isEmpty) NoType else if (cls is Module) cls.owner.thisType select sourceModule else createSymbol(self) + // pre-set info, so that parent types can refer to type params denot.info = ClassInfo(cls.owner.thisType, cls, Nil, decls, selfInfo) + + // Ensure constructor is completed so that any parameter accessors + // which have type trees deriving from its parameters can be + // completed in turn. Note that parent types access such parameter + // accessors, that's why the constructor needs to be completed before + // the parent types are elaborated. + index(constr) + symbolOfTree(constr).ensureCompleted() + val parentTypes = ensureFirstIsClass(parents map checkedParentType) val parentRefs = ctx.normalizeToClassRefs(parentTypes, cls, decls) typr.println(s"completing $denot, parents = $parents, parentTypes = $parentTypes, parentRefs = $parentRefs") - index(constr) index(rest)(inClassContext(selfInfo)) denot.info = ClassInfo(cls.owner.thisType, cls, parentRefs, decls, selfInfo) + // make sure constr parameters are all entered because we refer to them in desugarings: } } @@ -502,13 +524,6 @@ class Namer { typer: Typer => if (!mdef.tpt.isEmpty) WildcardType else { - /** Context where `sym` is defined */ - def defContext(sym: Symbol) = - ctx.outersIterator - .dropWhile(_.owner != sym) - .dropWhile(_.owner == sym) - .next - /** An type for this definition that might be inherited from elsewhere: * If this is a setter parameter, the corresponding getter type. * If this is a class member, the conjunction of all result types @@ -516,10 +531,7 @@ class Namer { typer: Typer => * NoType if neither case holds. */ val inherited = - if ((sym is Param) && sym.owner.isSetter) // fill in type from getter result type - defContext(sym.owner) - .denotNamed(sym.owner.asTerm.name.setterToGetter).info.widenExpr - else if (sym.owner.isTerm) NoType + if (sym.owner.isTerm) NoType else { // TODO: Look only at member of supertype instead? lazy val schema = paramFn(WildcardType) @@ -557,7 +569,7 @@ class Namer { typer: Typer => if (original.isConstructorName && (sym.owner is ModuleClass)) sym.owner.companionClass.info.decl(nme.CONSTRUCTOR) else - defContext(sym).denotNamed(original) + ctx.defContext(sym).denotNamed(original) def paramProto(paramss: List[List[Type]], idx: Int): Type = paramss match { case params :: paramss1 => if (idx < params.length) wildApprox(params(idx)) @@ -578,7 +590,7 @@ class Namer { typer: Typer => val rhsCtx = ctx.fresh addMode Mode.InferringReturnType def rhsType = typedAheadExpr(mdef.rhs, rhsProto)(rhsCtx).tpe.widen.approximateUnion def lhsType = fullyDefinedType(rhsType, "right-hand side", mdef.pos) - inherited orElse lhsType + inherited orElse lhsType orElse WildcardType } paramFn(typedAheadType(mdef.tpt, pt).tpe) } diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index f961a4544dd9..67e5c59024fe 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -635,11 +635,29 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } def typedTypeTree(tree: untpd.TypeTree, pt: Type)(implicit ctx: Context): TypeTree = track("typedTypeTree") { - val original1 = typed(tree.original) - val ownType = - if (original1.isEmpty) { assert(isFullyDefined(pt, ForceDegree.none)); pt } - else original1.tpe - cpy.TypeTree(tree, original1) withType ownType + if (tree.original.isEmpty) + tree match { + case tree: untpd.DerivedTypeTree => + tree.ensureCompletions + try + TypeTree(tree.derivedType(tree.attachment(untpd.OriginalSymbol))) withPos tree.pos + // btw, no need to remove the attachment. The typed + // tree is different from the untyped one, so the + // untyped tree is no longer accessed after all + // accesses with typedTypeTree are done. + catch { + case ex: NoSuchElementException => + println(s"missing OriginalSymbol for ${ctx.owner.ownersIterator.toList}") + throw ex + } + case _ => + assert(isFullyDefined(pt, ForceDegree.none)) + tree.withType(pt) + } + else { + val original1 = typed(tree.original) + cpy.TypeTree(tree, original1).withType(original1.tpe) + } } def typedSingletonTypeTree(tree: untpd.SingletonTypeTree)(implicit ctx: Context): SingletonTypeTree = track("typedSingletonTypeTree") { diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index 0caef3cae20f..1ddd0a578d75 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -18,6 +18,7 @@ class tests extends CompilerTest { val posDir = "./tests/pos/" val negDir = "./tests/neg/" + val newDir = "./tests/new/" val dotcDir = "./src/dotty/" /* @Test def pos_Coder() = compileFile(posDir, "Coder", twice) @@ -46,6 +47,7 @@ class tests extends CompilerTest { @Test def pos_approximateUnion = compileFile(posDir, "approximateUnion", twice) */ @Test def pos_all = compileFiles(posDir, twice) + @Test def pos_new = compileFiles(newDir, "-Xprompt" :: Nil) @Test def neg_blockescapes() = compileFile(negDir, "blockescapesNeg", xerrors = 1) @Test def neg_typedapply() = compileFile(negDir, "typedapply", xerrors = 4) diff --git a/test/test/ShowClassTests.scala b/test/test/ShowClassTests.scala index f683b26e7621..46f9e385e247 100644 --- a/test/test/ShowClassTests.scala +++ b/test/test/ShowClassTests.scala @@ -66,7 +66,7 @@ class ShowClassTests extends DottyTest { showPackage(ctx.requiredPackage(path)) val nstubs = Symbols.stubs.length debug_println(s"$nstubs stubs") - assert(nstubs <= expectedStubs, s"stubs found $nstubs, expected: $expectedStubs") + assert(nstubs <= expectedStubs, s"stubs found: $nstubs, expected: $expectedStubs\nstubs: ${Symbols.stubs.mkString(",")}") } def showClass(cls: Symbol)(implicit ctx: Context) = { diff --git a/tests/pos/A.scala b/tests/pos/A.scala new file mode 100644 index 000000000000..fc50379d88f6 --- /dev/null +++ b/tests/pos/A.scala @@ -0,0 +1,8 @@ +trait A extends java.lang.Object {} + +object test { + + def x: A = x; + +} + diff --git a/tests/pos/hygiene.scala b/tests/pos/hygiene.scala new file mode 100644 index 000000000000..9bbf73c0f9e0 --- /dev/null +++ b/tests/pos/hygiene.scala @@ -0,0 +1,20 @@ +// Illustrates a use case where we need hygiene. + +object hygiene { + + class D[T] + + case class C[T](x: D[T]) +// without hygiene, this gave +// 7: error: wrong number of type arguments for hygiene.C.D, should be 0 +// 7: error: constructor C in class C does not take type parameters + + object C { + class C + } + + val c = C.apply(new D) + + c.x + +} diff --git a/tests/pos/t0017.scala b/tests/pos/t0017.scala new file mode 100644 index 000000000000..d2bcda08d486 --- /dev/null +++ b/tests/pos/t0017.scala @@ -0,0 +1,21 @@ +class Quantity { + def getValue = 0; + def connect(c: Constraint) = c.newValue; +} + +abstract class Constraint(q: Quantity) { + def newValue: Unit; + q connect this +} + +class Adder(q: Quantity) extends Constraint(q) { + def newValue = Console.println(q.getValue); +} + +object Main { + def main(args: Array[String]): Unit = { + val x = new Quantity; + new Adder(x); + () + } +} diff --git a/tests/pos/t0020.scala b/tests/pos/t0020.scala new file mode 100644 index 000000000000..4f1e5b1732a9 --- /dev/null +++ b/tests/pos/t0020.scala @@ -0,0 +1,8 @@ +object Exceptions { + + class CubeException(s: String) extends RuntimeException(s); + + def main(args: Array[String]) = + Console.println(new CubeException("test")); + +} diff --git a/tests/pos/t0029.scala b/tests/pos/t0029.scala new file mode 100644 index 000000000000..937b6d70c049 --- /dev/null +++ b/tests/pos/t0029.scala @@ -0,0 +1,3 @@ +object Main { + def f[a]: List[List[a]] = for (l1 <- Nil; l2 <- Nil) yield l1 +} diff --git a/tests/pos/t0030.scala b/tests/pos/t0030.scala new file mode 100644 index 000000000000..2f23be14d98a --- /dev/null +++ b/tests/pos/t0030.scala @@ -0,0 +1,9 @@ +trait A { + def f(x: Int): Unit; + def f(x: String): Unit; +} + +class B extends A { + def f(x: Int): Unit = (); + def f(x: String): Unit = (); +} diff --git a/tests/pos/t0031.scala b/tests/pos/t0031.scala new file mode 100644 index 000000000000..d4050c818441 --- /dev/null +++ b/tests/pos/t0031.scala @@ -0,0 +1,29 @@ +object Main { + + trait Ensure[a] { + def ensure(postcondition: a => Boolean): a + } + + def require[a](precondition: => Boolean)(command: => a): Ensure[a] = + if (precondition) + new Ensure[a] { + def ensure(postcondition: a => Boolean): a = { + val result = command; + if (postcondition(result)) result + else sys.error("Assertion error") + } + } + else + sys.error("Assertion error"); + + def arb[a](s: List[a]) = + require (! s.isEmpty) { + s.head + } ensure (result => s contains result); + + def main(args: Array[String]) = { + val s = List(1, 2); + Console.println(arb(s)) + } + +} diff --git a/tests/pos/t0032.scala b/tests/pos/t0032.scala new file mode 100644 index 000000000000..727a7d4e992d --- /dev/null +++ b/tests/pos/t0032.scala @@ -0,0 +1,17 @@ +import java.io.{OutputStream, PrintStream}; + +class PromptStream(s: OutputStream) extends PrintStream(s) { + override def println() = super.println(); +} + +object Main { + + val out = new PromptStream(java.lang.System.out); + + java.lang.System.setOut(out); + + def main(args: Array[String]) = + //out.println("hello world"); + () + +} diff --git a/tests/pos/t0036.scala b/tests/pos/t0036.scala new file mode 100644 index 000000000000..3c9a84f8ad33 --- /dev/null +++ b/tests/pos/t0036.scala @@ -0,0 +1,8 @@ +object m { + + val xs: List[Int] = Nil + def f(i: Int) = 0 + val v = xs map f + + def m() = {} +} diff --git a/tests/new/t0039.scala b/tests/pos/t0039.scala similarity index 100% rename from tests/new/t0039.scala rename to tests/pos/t0039.scala diff --git a/tests/pos/t0049.scala b/tests/pos/t0049.scala new file mode 100644 index 000000000000..dd866422637f --- /dev/null +++ b/tests/pos/t0049.scala @@ -0,0 +1,3 @@ +class C1(x: AnyRef) {}; + +class C2 extends C1({ class A extends AnyRef {}; (new A) : AnyRef }) {}; diff --git a/tests/pos/t0053.scala b/tests/pos/t0053.scala new file mode 100644 index 000000000000..44763ef144f3 --- /dev/null +++ b/tests/pos/t0053.scala @@ -0,0 +1,7 @@ +object bug { + def foobar[c]: Int = { + class Foo { def foo: Bar = new Bar(); } + class Bar { def bar: c = bar; } + 0 + } +} diff --git a/tests/pos/t0055.scala b/tests/pos/t0055.scala new file mode 100644 index 000000000000..0796294403a3 --- /dev/null +++ b/tests/pos/t0055.scala @@ -0,0 +1,6 @@ +class X(x : Any) +class W { + new X(new Z() with Y) {} + trait Y { def y = () } +} +class Z(r : Any) { def this() = this(null) } diff --git a/tests/pos/t0061.scala b/tests/pos/t0061.scala new file mode 100644 index 000000000000..8a3aed7c6057 --- /dev/null +++ b/tests/pos/t0061.scala @@ -0,0 +1,10 @@ +object O { + + class testClass ; + + case class testA() extends testClass ; + + def ga( x:testClass ) = x match { + case testA() => () + } +} diff --git a/tests/pos/t0064.scala b/tests/pos/t0064.scala new file mode 100644 index 000000000000..1eeca8dcad44 --- /dev/null +++ b/tests/pos/t0064.scala @@ -0,0 +1,6 @@ +object B { + def main(Args:Array[String]) = { + val (_,x) = (1,2); + x + 1; + } +} diff --git a/tests/pos/t0066.scala b/tests/pos/t0066.scala new file mode 100644 index 000000000000..8ac328908030 --- /dev/null +++ b/tests/pos/t0066.scala @@ -0,0 +1,7 @@ +class GBTree[A, B] { + abstract class Tree[A,B]; + case class Node[A,B](key:A,value:B,smaller:Node[A,B],bigger:Node[A,B]) + extends Tree[A,B]; + case class Nil[A,B]() extends Tree[A,B]; + +} diff --git a/tests/pos/t0068.scala b/tests/pos/t0068.scala new file mode 100644 index 000000000000..beb2c7c0abbd --- /dev/null +++ b/tests/pos/t0068.scala @@ -0,0 +1,6 @@ +class E { + def f() = { + val (_::l1) = List(1,2,3); + l1.tail; + } +} diff --git a/tests/pos/t0069.scala b/tests/pos/t0069.scala new file mode 100644 index 000000000000..23a25dbec5b5 --- /dev/null +++ b/tests/pos/t0069.scala @@ -0,0 +1,5 @@ +object testCQ { + + case class Thing( name:String, contains:List[ Thing ] ); + +} diff --git a/tests/pos/t0076.scala b/tests/pos/t0076.scala new file mode 100644 index 000000000000..bac26f2ab566 --- /dev/null +++ b/tests/pos/t0076.scala @@ -0,0 +1,8 @@ +object bug { + def foo(i: => Int): Int = 0; + + def bar: Int = { + var i: Int = 0; + foo (i); + } +} diff --git a/tests/pos/t0081.scala b/tests/pos/t0081.scala new file mode 100644 index 000000000000..20fd60497437 --- /dev/null +++ b/tests/pos/t0081.scala @@ -0,0 +1,4 @@ +class A { + val b: A#B = new B; + class B {} +} diff --git a/tests/pos/t0082.scala b/tests/pos/t0082.scala new file mode 100644 index 000000000000..2a9e549b11e5 --- /dev/null +++ b/tests/pos/t0082.scala @@ -0,0 +1,17 @@ + +object Main { + + def min0[A](less: (A, A) => Boolean, xs: List[A]): Option[A] = xs match { + case List() => None + case List(x) => Some(x) + case y :: ys => (min0(less, ys): @unchecked) match { + case Some(m) => if (less(y, m)) Some(y) else Some(m) + } + } + + def min(xs: List[Int]) = min0((x: Int, y: Int) => x < y, xs); + + def main(args: Array[String]) = + Console.println(min(List())); + +} diff --git a/tests/pos/t0085.scala b/tests/pos/t0085.scala new file mode 100644 index 000000000000..e018afb6ee02 --- /dev/null +++ b/tests/pos/t0085.scala @@ -0,0 +1,8 @@ +object A { + case class B(c: C) { + class C; + } + class C; + val b: B = new B(new C()); + val c: C = b.c; +} diff --git a/tests/pos/t0091.scala b/tests/pos/t0091.scala new file mode 100644 index 000000000000..414e2c931ab7 --- /dev/null +++ b/tests/pos/t0091.scala @@ -0,0 +1,6 @@ +class Bug { + def main(args: Array[String]) = { + var msg: String = null; + val f: PartialFunction[Any, Unit] = { case 42 => msg = "coucou" }; + } +} diff --git a/tests/pos/t0093.scala b/tests/pos/t0093.scala new file mode 100644 index 000000000000..d648d773b08c --- /dev/null +++ b/tests/pos/t0093.scala @@ -0,0 +1,4 @@ +object Bug { + def f(cond: => Boolean) = while (cond == false) {}; + // no bug with "false == cond" +} diff --git a/tests/pos/t0095.scala b/tests/pos/t0095.scala new file mode 100644 index 000000000000..2123237b5412 --- /dev/null +++ b/tests/pos/t0095.scala @@ -0,0 +1,15 @@ +class ParseResult[+T] +case class Success[+T](t: T) extends ParseResult[T] + +abstract class Nonterminal[Output] { + + type SubNonterminal = Nonterminal[_ <: Output] + + def parse: ParseResult[Output] + + def parse1(nts: List[SubNonterminal]): ParseResult[Output] = + nts match { + case nt::nts => nt.parse match { case Success(so) => Success(so) } + case Nil => throw new Error + } +}