diff options
24 files changed, 423 insertions, 118 deletions
diff --git a/docs/SyntaxSummary.txt b/docs/SyntaxSummary.txt index e40b3fd6c..1bbdc84d7 100644 --- a/docs/SyntaxSummary.txt +++ b/docs/SyntaxSummary.txt @@ -99,8 +99,9 @@ grammar. FunArgTypes ::= InfixType | `(' [ FunArgType {`,' FunArgType } ] `)' InfixType ::= RefinedType {id [nl] RefinedType} InfixOp(t1, op, t2) - RefinedType ::= WithType {Annotation | [nl] Refinement} Annotated(t, annot), RefinedTypeTree(t, ds) - WithType ::= SimpleType {`with' SimpleType} (deprecated) + RefinedType ::= WithType {[nl] Refinement} RefinedTypeTree(t, ds) + WithType ::= AnnotType {`with' AnnotType} (deprecated) + AnnotType ::= SimpleType {Annotation} Annotated(t, annot) SimpleType ::= SimpleType TypeArgs AppliedTypeTree(t, args) | SimpleType `#' id SelectFromTypeTree(t, name) | StableId @@ -121,9 +122,9 @@ grammar. Expr ::= FunParams `=>' Expr Function(args, expr), Function(ValDef([implicit], id, TypeTree(), EmptyTree), expr) | Expr1 - FunParams ::= Bindings - | [`implicit'] id - | `_' + FunParams ::= Bindings + | [`implicit'] id + | `_' ExprInParens ::= PostfixExpr `:' Type | Expr BlockResult ::= (FunParams | [`implicit'] id `:' InfixType) => Block @@ -248,7 +249,7 @@ grammar. AccessModifier ::= (`private' | `protected') [AccessQualifier] AccessQualifier ::= `[' (id | `this') `]' - Annotation ::= `@' SimpleType {ArgumentExprs} Apply(tpe, args) + Annotation ::= `@' SimpleType {ParArgumentExprs} Apply(tpe, args) TemplateBody ::= [nl] `{' [SelfType] TemplateStat {semi TemplateStat} `} (self, stats) TemplateStat ::= Import @@ -301,7 +302,7 @@ grammar. TemplateOpt ::= [`extends' Template | [nl] TemplateBody] Template ::= ConstrApps [TemplateBody] | TemplateBody Template(constr, parents, self, stats) ConstrApps ::= ConstrApp {`with' ConstrApp} - ConstrApp ::= SimpleType {ArgumentExprs} Apply(tp, args) + ConstrApp ::= AnnotType {ArgumentExprs} Apply(tp, args) ConstrExpr ::= SelfInvocation | ConstrBlock diff --git a/src/dotty/tools/backend/jvm/GenBCode.scala b/src/dotty/tools/backend/jvm/GenBCode.scala index 7729c3011..db376a452 100644 --- a/src/dotty/tools/backend/jvm/GenBCode.scala +++ b/src/dotty/tools/backend/jvm/GenBCode.scala @@ -38,7 +38,7 @@ class GenBCode extends Phase { def run(implicit ctx: Context): Unit = { - new GenBCodePipeline(entryPoints.toList, new DottyBackendInterface()(ctx))(ctx).run(ctx.compilationUnit.tpdTree) + new GenBCodePipeline(entryPoints.toList, new DottyBackendInterface()(ctx))(ctx).run(ctx.compilationUnit.tpdTree) entryPoints.clear() } } diff --git a/src/dotty/tools/dotc/config/CompilerCommand.scala b/src/dotty/tools/dotc/config/CompilerCommand.scala index 629042291..3ba8db3ba 100644 --- a/src/dotty/tools/dotc/config/CompilerCommand.scala +++ b/src/dotty/tools/dotc/config/CompilerCommand.scala @@ -110,19 +110,19 @@ object CompilerCommand extends DotClass { if (summary.errors.nonEmpty) { summary.errors foreach (ctx.error(_)) - ctx.echo(" dotc -help gives more information") + ctx.println(" dotc -help gives more information") Nil } else if (settings.version.value) { - ctx.echo(versionMsg) + ctx.println(versionMsg) Nil } else if (shouldStopWithInfo) { - ctx.echo(infoMessage) + ctx.println(infoMessage) Nil } else { if (summary.arguments.isEmpty && !settings.resident.value) - ctx.echo(usageMessage) + ctx.println(usageMessage) summary.arguments } } diff --git a/src/dotty/tools/dotc/config/Config.scala b/src/dotty/tools/dotc/config/Config.scala index 38ebca078..27d5effa5 100644 --- a/src/dotty/tools/dotc/config/Config.scala +++ b/src/dotty/tools/dotc/config/Config.scala @@ -71,4 +71,31 @@ object Config { /** Check that certain types cannot be created in erasedTypes phases */ final val checkUnerased = true + + + /** Initial size of superId table */ + final val InitialSuperIdsSize = 4096 + + /** Initial capacity of uniques HashMap */ + final val initialUniquesCapacity = 40000 + + /** How many recursive calls to NamedType#underlying are performed before logging starts. */ + final val LogPendingUnderlyingThreshold = 50 + + /** How many recursive calls to isSubType are performed before logging starts. */ + final val LogPendingSubTypesThreshold = 50 + + /** How many recursive calls to findMember are performed before logging names starts + * Note: this threshold has to be chosen carefully. Too large, and programs + * like tests/pos/IterableSelfRec go into polynomial (or even exponential?) + * compile time slowdown. Too small and normal programs will cause the compiler to + * do inefficient operations on findMember. The current value is determined + * so that (1) IterableSelfRec still compiles in reasonable time (< 10sec) (2) Compiling + * dotty itself only causes small pending names lists to be generated (we measured + * at max 6 elements) and these lists are never searched with contains. + */ + final val LogPendingFindMemberThreshold = 10 + + /** Maximal number of outstanding recursive calls to findMember */ + final val PendingFindMemberLimit = LogPendingFindMemberThreshold * 4 } diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala index 5d2750aa8..c1b2e20eb 100644 --- a/src/dotty/tools/dotc/core/Contexts.scala +++ b/src/dotty/tools/dotc/core/Contexts.scala @@ -20,6 +20,7 @@ import util.{FreshNameCreator, SimpleMap, SourceFile, NoSource} import typer._ import Implicits.ContextualImplicits import config.Settings._ +import config.Config import reporting._ import collection.mutable import collection.immutable.BitSet @@ -164,6 +165,14 @@ object Contexts { _typeComparer } + /** Number of findMember calls on stack */ + private[core] var findMemberCount: Int = 0 + + /** List of names which have a findMemberCall on stack, + * after Config.LogPendingFindMemberThreshold is reached. + */ + private[core] var pendingMemberSearches: List[Name] = Nil + /** The new implicit references that are introduced by this scope */ private var implicitsCache: ContextualImplicits = null def implicits: ContextualImplicits = { @@ -508,7 +517,7 @@ object Contexts { def nextId = { _nextId += 1; _nextId } /** A map from a superclass id to the typeref of the class that has it */ - private[core] var classOfId = new Array[ClassSymbol](InitialSuperIdsSize) + private[core] var classOfId = new Array[ClassSymbol](Config.InitialSuperIdsSize) /** A map from a the typeref of a class to its superclass id */ private[core] val superIdOfClass = new mutable.AnyRefMap[ClassSymbol, Int] @@ -529,7 +538,7 @@ object Contexts { // Types state /** A table for hash consing unique types */ - private[core] val uniques = new util.HashSet[Type](initialUniquesCapacity) { + private[core] val uniques = new util.HashSet[Type](Config.initialUniquesCapacity) { override def hash(x: Type): Int = x.hash } @@ -614,20 +623,4 @@ object Contexts { myBounds = myBounds.updated(sym, b) def bounds = myBounds } - - /** Initial size of superId table */ - private final val InitialSuperIdsSize = 4096 - - /** Initial capacity of uniques HashMap */ - private[core] final val initialUniquesCapacity = 40000 - - /** How many recursive calls to NamedType#underlying are performed before - * logging starts. - */ - private[core] final val LogPendingUnderlyingThreshold = 50 - - /** How many recursive calls to isSubType are performed before - * logging starts. - */ - private[core] final val LogPendingSubTypesThreshold = 50 } diff --git a/src/dotty/tools/dotc/core/Decorators.scala b/src/dotty/tools/dotc/core/Decorators.scala index 8aaef985c..d90b959ab 100644 --- a/src/dotty/tools/dotc/core/Decorators.scala +++ b/src/dotty/tools/dotc/core/Decorators.scala @@ -173,7 +173,7 @@ object Decorators { def treatSingleArg(arg: Any) : Any = try arg match { - case arg: Showable => arg.show(ctx.fresh.addMode(Mode.FutureDefsOK)) + case arg: Showable => arg.show(ctx.addMode(Mode.FutureDefsOK)) case _ => arg } catch { diff --git a/src/dotty/tools/dotc/core/NameOps.scala b/src/dotty/tools/dotc/core/NameOps.scala index 60aacd894..bf5e219cf 100644 --- a/src/dotty/tools/dotc/core/NameOps.scala +++ b/src/dotty/tools/dotc/core/NameOps.scala @@ -99,12 +99,18 @@ object NameOps { /** Is this the name of a higher-kinded type parameter of a Lambda? */ def isLambdaArgName = - name.length > 0 && name.head == tpnme.LAMBDA_ARG_PREFIXhead && name.startsWith(tpnme.LAMBDA_ARG_PREFIX) + name.length > 0 && + name.head == tpnme.LAMBDA_ARG_PREFIXhead && + name.startsWith(tpnme.LAMBDA_ARG_PREFIX) && { + val digits = name.drop(tpnme.LAMBDA_ARG_PREFIX.length) + digits.length <= 4 && digits.forall(_.isDigit) + } /** The index of the higher-kinded type parameter with this name. * Pre: isLambdaArgName. */ - def lambdaArgIndex: Int = name.drop(name.lastIndexOf('$') + 1).toString.toInt + def lambdaArgIndex: Int = + name.drop(tpnme.LAMBDA_ARG_PREFIX.length).toString.toInt /** If the name ends with $nn where nn are * all digits, strip the $ and the digits. diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala index 14d6bedc7..6273612c7 100644 --- a/src/dotty/tools/dotc/core/StdNames.scala +++ b/src/dotty/tools/dotc/core/StdNames.scala @@ -172,7 +172,7 @@ object StdNames { final val WILDCARD_STAR: N = "_*" final val REIFY_TREECREATOR_PREFIX: N = "$treecreator" final val REIFY_TYPECREATOR_PREFIX: N = "$typecreator" - final val LAMBDA_ARG_PREFIX: N = "$hkArg$" + final val LAMBDA_ARG_PREFIX: N = "HK$" final val LAMBDA_ARG_PREFIXhead: Char = LAMBDA_ARG_PREFIX.head final val Any: N = "Any" diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala index 8bd1651dc..7f3f8a446 100644 --- a/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/src/dotty/tools/dotc/core/TypeApplications.scala @@ -515,17 +515,19 @@ class TypeApplications(val self: Type) extends AnyVal { self.appliedTo(tparams map (_.typeRef)).LambdaAbstract(tparams) } - /** Test whether this type has a base type `B[T1, ..., Tn]` where the type parameters - * of `B` match one-by-one the variances of `tparams`, and where the lambda - * abstracted type + /** Test whether this type has a base type of the form `B[T1, ..., Bn]` where + * the type parameters of `B` match one-by-one the variances of `tparams`, + * and where the lambda abstracted type * * LambdaXYZ { type Apply = B[$hkArg$0, ..., $hkArg$n] } * { type $hkArg$0 = T1; ...; type $hkArg$n = Tn } * * satisfies predicate `p`. Try base types in the order of their occurrence in `baseClasses`. * A type parameter matches a variance V if it has V as its variance or if V == 0. + * @param classBounds A hint to bound the search. Only types that derive from one of the + * classes in classBounds are considered. */ - def testLifted(tparams: List[Symbol], p: Type => Boolean)(implicit ctx: Context): Boolean = { + def testLifted(tparams: List[Symbol], p: Type => Boolean, classBounds: List[ClassSymbol])(implicit ctx: Context): Boolean = { def tryLift(bcs: List[ClassSymbol]): Boolean = bcs match { case bc :: bcs1 => val tp = self.baseTypeWithArgs(bc) @@ -533,7 +535,8 @@ class TypeApplications(val self: Type) extends AnyVal { val tycon = tp.withoutArgs(targs) def variancesMatch(param1: Symbol, param2: Symbol) = param2.variance == param2.variance || param2.variance == 0 - if ((tycon.typeParams corresponds tparams)(variancesMatch)) { + if (classBounds.exists(tycon.derivesFrom(_)) && + tycon.typeParams.corresponds(tparams)(variancesMatch)) { val expanded = tycon.EtaExpand val lifted = (expanded /: targs) { (partialInst, targ) => val tparam = partialInst.typeParams.head @@ -548,7 +551,7 @@ class TypeApplications(val self: Type) extends AnyVal { false } if (tparams.isEmpty) false - else if (typeParams.nonEmpty) p(EtaExpand) || tryLift(self.baseClasses) - else tryLift(self.baseClasses) + else if (typeParams.nonEmpty) p(EtaExpand) || classBounds.nonEmpty && tryLift(self.baseClasses) + else classBounds.nonEmpty && tryLift(self.baseClasses) } } diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index 18f9f08bb..069525db0 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -97,7 +97,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi try { recCount = recCount + 1 val result = - if (recCount < LogPendingSubTypesThreshold) firstTry(tp1, tp2) + if (recCount < Config.LogPendingSubTypesThreshold) firstTry(tp1, tp2) else monitoredIsSubType(tp1, tp2) recCount = recCount - 1 if (!result) constraint = saved @@ -345,7 +345,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi || fourthTry(tp1, tp2) ) normalPath || - needsEtaLift(tp1, tp2) && tp1.testLifted(tp2.typeParams, isSubType(_, tp2)) + needsEtaLift(tp1, tp2) && tp1.testLifted(tp2.typeParams, isSubType(_, tp2), classBounds(tp2)) } else // fast path, in particular for refinements resulting from parameterization. isSubType(tp1, skipped2) && @@ -453,7 +453,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi isNewSubType(tp1.underlying.widenExpr, tp2) || comparePaths case tp1: RefinedType => isNewSubType(tp1.parent, tp2) || - needsEtaLift(tp2, tp1) && tp2.testLifted(tp1.typeParams, isSubType(tp1, _)) + needsEtaLift(tp2, tp1) && tp2.testLifted(tp1.typeParams, isSubType(tp1, _), Nil) case AndType(tp11, tp12) => eitherIsSubType(tp11, tp2, tp12, tp2) case JavaArrayType(elem1) => @@ -475,9 +475,13 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi val lambda = projection.prefix.LambdaClass(forcing = true) lambda.exists && !other.isLambda && other.testLifted(lambda.typeParams, - if (inOrder) isSubType(projection.prefix, _) else isSubType(_, projection.prefix)) + if (inOrder) isSubType(projection.prefix, _) else isSubType(_, projection.prefix), + if (inOrder) Nil else classBounds(projection.prefix)) } + /** The class symbols bounding the type of the `Apply` member of `tp` */ + private def classBounds(tp: Type) = tp.member(tpnme.Apply).info.classSymbols + /** Returns true iff either `tp11 <:< tp21` or `tp12 <:< tp22`, trying at the same time * to keep the constraint as wide as possible. Specifically, if * @@ -1141,13 +1145,13 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi } /** Show subtype goal that led to an assertion failure */ - def showGoal(tp1: Type, tp2: Type) = { - println(disambiguated(implicit ctx => s"assertion failure for ${tp1.show} <:< ${tp2.show}, frozen = $frozenConstraint")) + def showGoal(tp1: Type, tp2: Type)(implicit ctx: Context) = { + ctx.println(disambiguated(implicit ctx => s"assertion failure for ${tp1.show} <:< ${tp2.show}, frozen = $frozenConstraint")) def explainPoly(tp: Type) = tp match { - case tp: PolyParam => println(s"polyparam ${tp.show} found in ${tp.binder.show}") - case tp: TypeRef if tp.symbol.exists => println(s"typeref ${tp.show} found in ${tp.symbol.owner.show}") - case tp: TypeVar => println(s"typevar ${tp.show}, origin = ${tp.origin}") - case _ => println(s"${tp.show} is a ${tp.getClass}") + case tp: PolyParam => ctx.println(s"polyparam ${tp.show} found in ${tp.binder.show}") + case tp: TypeRef if tp.symbol.exists => ctx.println(s"typeref ${tp.show} found in ${tp.symbol.owner.show}") + case tp: TypeVar => ctx.println(s"typevar ${tp.show}, origin = ${tp.origin}") + case _ => ctx.println(s"${tp.show} is a ${tp.getClass}") } explainPoly(tp1) explainPoly(tp2) diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala index 1adabbd2d..acbd5b6f0 100644 --- a/src/dotty/tools/dotc/core/TypeOps.scala +++ b/src/dotty/tools/dotc/core/TypeOps.scala @@ -302,18 +302,19 @@ trait TypeOps { this: Context => // TODO: Make standalone object. // println(s"normalizing $parents of $cls in ${cls.owner}") // !!! DEBUG var refinements: SimpleMap[TypeName, Type] = SimpleMap.Empty var formals: SimpleMap[TypeName, Symbol] = SimpleMap.Empty - def normalizeToRef(tp: Type): TypeRef = tp match { + def normalizeToRef(tp: Type): TypeRef = tp.dealias match { + case tp: TypeRef => + tp case tp @ RefinedType(tp1, name: TypeName) => val prevInfo = refinements(name) refinements = refinements.updated(name, if (prevInfo == null) tp.refinedInfo else prevInfo & tp.refinedInfo) formals = formals.updated(name, tp1.typeParamNamed(name)) normalizeToRef(tp1) - case tp: TypeRef => - if (tp.symbol.info.isAlias) normalizeToRef(tp.info.bounds.hi) - else tp case ErrorType => defn.AnyClass.typeRef + case AnnotatedType(_, tpe) => + normalizeToRef(tpe) case _ => throw new TypeError(s"unexpected parent type: $tp") } diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 3ab621db1..ae9088f00 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -35,8 +35,6 @@ import language.implicitConversions object Types { - private var recCount = 0 // used temporarily for debugging. TODO: remove - private var nextId = 0 /** The class of types. @@ -417,9 +415,7 @@ object Types { * as seen from given prefix `pre`. Exclude all members that have * flags in `excluded` from consideration. */ - final def findMember(name: Name, pre: Type, excluded: FlagSet)(implicit ctx: Context): Denotation = try { - recCount += 1 - assert(recCount < 40) + final def findMember(name: Name, pre: Type, excluded: FlagSet)(implicit ctx: Context): Denotation = { @tailrec def go(tp: Type): Denotation = tp match { case tp: RefinedType => if (name eq tp.refinedName) goRefined(tp) else go(tp.parent) @@ -456,7 +452,11 @@ object Types { if (tp.refinementRefersToThis) tp.refinedInfo.substSkolem(tp, pre) else tp.refinedInfo if (name.isTypeName) { // simplified case that runs more efficiently - val jointInfo = if (rinfo.isAlias) rinfo else pdenot.info & rinfo + val jointInfo = + if (rinfo.isAlias) rinfo + else if (pdenot.info.isAlias) pdenot.info + else if (ctx.pendingMemberSearches.contains(name)) safeAnd(pdenot.info, rinfo) + else pdenot.info & rinfo pdenot.asSingleDenotation.derivedSingleDenotation(pdenot.symbol, jointInfo) } else pdenot & (new JointRefDenotation(NoSymbol, rinfo, Period.allInRun(ctx.runId)), pre) @@ -488,15 +488,31 @@ object Types { } def goAnd(l: Type, r: Type) = go(l) & (go(r), pre) def goOr(l: Type, r: Type) = go(l) | (go(r), pre) - go(this) - } catch { - case ex: MergeError => - throw new MergeError(s"${ex.getMessage} as members of type ${pre.show}") - case ex: Throwable => - println(s"findMember exception for $this member $name") - throw ex // DEBUG - } finally { - recCount -= 1 + def safeAnd(tp1: Type, tp2: Type): Type = (tp1, tp2) match { + case (TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) => TypeBounds(lo1 | lo2, AndType(hi1, hi2)) + case _ => tp1 & tp2 + } + + { val recCount = ctx.findMemberCount + 1 + ctx.findMemberCount = recCount + if (recCount >= Config.LogPendingFindMemberThreshold) + ctx.pendingMemberSearches = name :: ctx.pendingMemberSearches + } + + try go(this) + catch { + case ex: MergeError => + throw new MergeError(s"${ex.getMessage} as members of type ${pre.show}") + case ex: Throwable => + ctx.println(i"findMember exception for $this member $name") + throw ex // DEBUG + } + finally { + val recCount = ctx.findMemberCount + if (recCount >= Config.LogPendingFindMemberThreshold) + ctx.pendingMemberSearches = ctx.pendingMemberSearches.tail + ctx.findMemberCount = recCount - 1 + } } /** The set of names of members of this type that pass the given name filter @@ -729,6 +745,12 @@ object Types { case tp => tp } + /** If this is a TypeAlias type, its alias otherwise this type itself */ + final def followTypeAlias(implicit ctx: Context): Type = this match { + case TypeAlias(alias) => alias + case _ => this + } + /** Perform successive widenings and dealiasings until none can be applied anymore */ final def widenDealias(implicit ctx: Context): Type = { val res = this.widen.dealias @@ -786,43 +808,73 @@ object Types { // ----- Normalizing typerefs over refined types ---------------------------- - /** If this is a refinement type that has a refinement for `name` (which might be followed + /** If this normalizes* to a refinement type that has a refinement for `name` (which might be followed * by other refinements), and the refined info is a type alias, return the alias, * otherwise return NoType. Used to reduce types of the form * * P { ... type T = / += / -= U ... } # T * * to just U. Does not perform the reduction if the resulting type would contain - * a reference to the "this" of the current refined type. But does follow - * aliases in order to avoid such references. Example: + * a reference to the "this" of the current refined type, except in the following situation * - * Lambda$I { type $hk$Arg0 = String, type Apply = Lambda$I{...}.$hk$Arg0 } # Apply + * (1) The "this" reference can be avoided by following an alias. Example: * - * Here, the refinement for `Apply` has a refined this node, yet dereferencing ones more - * yields `String` as the result of lookupRefined. + * P { type T = String, type R = P{...}.T } # R --> String + * + * (2) The refinement is a fully instantiated type lambda, and the projected name is "Apply". + * In this case the rhs of the apply is returned with all references to lambda argument types + * substituted by their definitions. + * + * (*) normalizes means: follow instantiated typevars and aliases. */ def lookupRefined(name: Name)(implicit ctx: Context): Type = { - def loop(pre: Type): Type = pre.stripTypeVar match { + def loop(pre: Type, resolved: List[Name]): Type = pre.stripTypeVar match { case pre: RefinedType => - if (pre.refinedName ne name) loop(pre.parent) - else pre.refinedInfo match { - case TypeAlias(tp) => - if (!pre.refinementRefersToThis) tp - else tp match { - case TypeRef(SkolemType(`pre`), alias) => lookupRefined(alias) - case _ => NoType + object instantiate extends TypeMap { + var isSafe = true + def apply(tp: Type): Type = tp match { + case TypeRef(SkolemType(`pre`), name) if name.isLambdaArgName => + val TypeAlias(alias) = member(name).info + alias + case tp: TypeVar if !tp.inst.exists => + isSafe = false + tp + case _ => + mapOver(tp) + } + } + def betaReduce(tp: Type) = { + val lam = pre.parent.LambdaClass(forcing = false) + if (lam.exists && lam.typeParams.forall(tparam => resolved.contains(tparam.name))) { + val reduced = instantiate(tp) + if (instantiate.isSafe) reduced else NoType + } + else NoType + } + pre.refinedInfo match { + case TypeAlias(alias) => + if (pre.refinedName ne name) loop(pre.parent, pre.refinedName :: resolved) + else if (!pre.refinementRefersToThis) alias + else alias match { + case TypeRef(SkolemType(`pre`), aliasName) => lookupRefined(aliasName) // (1) + case _ => if (name == tpnme.Apply) betaReduce(alias) else NoType // (2) } - case _ => loop(pre.parent) + case _ => loop(pre.parent, resolved) } case SkolemType(binder) => binder.lookupRefined(name) case pre: WildcardType => WildcardType + case pre: TypeRef => + pre.info match { + case TypeAlias(alias) => loop(alias, resolved) + case _ => NoType + } case _ => NoType } - loop(this) + loop(this, Nil) } /** The type <this . name> , reduced if possible */ @@ -1390,7 +1442,7 @@ object Types { def isTerm = isInstanceOf[TermRef] /** Guard against cycles that can arise if given `op` - * follows info. The prblematic cases are a type alias to itself or + * follows info. The problematic cases are a type alias to itself or * bounded by itself or a val typed as itself: * * type T <: T @@ -1401,7 +1453,7 @@ object Types { */ final def controlled[T](op: => T)(implicit ctx: Context): T = try { ctx.underlyingRecursions += 1 - if (ctx.underlyingRecursions < LogPendingUnderlyingThreshold) + if (ctx.underlyingRecursions < Config.LogPendingUnderlyingThreshold) op else if (ctx.pendingUnderlying contains this) throw CyclicReference(symbol) @@ -1751,6 +1803,11 @@ object Types { lazy val ref = refFn() override def underlying(implicit ctx: Context) = ref override def toString = s"LazyRef($ref)" + override def equals(other: Any) = other match { + case other: LazyRef => this.ref.equals(other.ref) + case _ => false + } + override def hashCode = ref.hashCode + 37 } // --- Refined Type --------------------------------------------------------- @@ -1842,7 +1899,7 @@ object Types { else make(RefinedType(parent, names.head, infoFns.head), names.tail, infoFns.tail) def apply(parent: Type, name: Name, infoFn: RefinedType => Type)(implicit ctx: Context): RefinedType = { - assert(!ctx.erasedTypes) + assert(!ctx.erasedTypes || ctx.mode.is(Mode.Printing)) ctx.base.uniqueRefinedTypes.enterIfNew(new CachedRefinedType(parent, name, infoFn)).checkInst } @@ -2590,7 +2647,7 @@ object Types { abstract class TypeAlias(val alias: Type, override val variance: Int) extends TypeBounds(alias, alias) { /** pre: this is a type alias */ def derivedTypeAlias(tp: Type, variance: Int = this.variance)(implicit ctx: Context) = - if (lo eq tp) this + if ((lo eq tp) && (variance == this.variance)) this else TypeAlias(tp, variance) override def & (that: TypeBounds)(implicit ctx: Context): TypeBounds = { diff --git a/src/dotty/tools/dotc/core/Uniques.scala b/src/dotty/tools/dotc/core/Uniques.scala index c24b0cabc..b00508d60 100644 --- a/src/dotty/tools/dotc/core/Uniques.scala +++ b/src/dotty/tools/dotc/core/Uniques.scala @@ -2,6 +2,7 @@ package dotty.tools.dotc package core import Types._, Contexts._, util.Stats._, Hashable._, Names._ +import config.Config import util.HashSet /** Defines operation `unique` for hash-consing types. @@ -39,7 +40,7 @@ object Uniques { ) */ - final class NamedTypeUniques extends HashSet[NamedType](initialUniquesCapacity) with Hashable { + final class NamedTypeUniques extends HashSet[NamedType](Config.initialUniquesCapacity) with Hashable { override def hash(x: NamedType): Int = x.hash private def findPrevious(h: Int, prefix: Type, name: Name): NamedType = { @@ -65,7 +66,7 @@ object Uniques { } } - final class TypeAliasUniques extends HashSet[TypeAlias](initialUniquesCapacity) with Hashable { + final class TypeAliasUniques extends HashSet[TypeAlias](Config.initialUniquesCapacity) with Hashable { override def hash(x: TypeAlias): Int = x.hash private def findPrevious(h: Int, alias: Type, variance: Int): TypeAlias = { @@ -90,7 +91,7 @@ object Uniques { } } - final class RefinedUniques extends HashSet[RefinedType](initialUniquesCapacity) with Hashable { + final class RefinedUniques extends HashSet[RefinedType](Config.initialUniquesCapacity) with Hashable { override val hashSeed = classOf[CachedRefinedType].hashCode // some types start life as CachedRefinedTypes, need to have same hash seed override def hash(x: RefinedType): Int = x.hash diff --git a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 84d497b9c..e753bdcab 100644 --- a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -720,7 +720,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { case SELECT => def readQual(name: Name) = { val localCtx = - if (name == nme.CONSTRUCTOR) ctx.fresh.addMode(Mode.InSuperCall) else ctx + if (name == nme.CONSTRUCTOR) ctx.addMode(Mode.InSuperCall) else ctx readTerm()(localCtx) } def readRest(name: Name, sig: Signature) = { diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala index dd2c9bcaa..b79077245 100644 --- a/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/src/dotty/tools/dotc/parsing/Parsers.scala @@ -679,25 +679,29 @@ object Parsers { def refinedTypeRest(t: Tree): Tree = { newLineOptWhenFollowedBy(LBRACE) - in.token match { - case AT => refinedTypeRest(atPos(t.pos.start) { Annotated(annot(), t) }) - case LBRACE => refinedTypeRest(atPos(t.pos.start) { RefinedTypeTree(t, refinement()) }) - case _ => t - } + if (in.token == LBRACE) refinedTypeRest(atPos(t.pos.start) { RefinedTypeTree(t, refinement()) }) + else t } - /** WithType ::= SimpleType {`with' SimpleType} (deprecated) + /** WithType ::= AnnotType {`with' AnnotType} (deprecated) */ - def withType(): Tree = withTypeRest(simpleType()) + def withType(): Tree = withTypeRest(annotType()) - def withTypeRest(t: Tree): Tree = { + def withTypeRest(t: Tree): Tree = if (in.token == WITH) { deprecationWarning("`with' as a type operator has been deprecated; use `&' instead") in.nextToken() AndTypeTree(t, withType()) } else t - } + + /** AnnotType ::= SimpleType {Annotation} + */ + def annotType(): Tree = annotTypeRest(simpleType()) + + def annotTypeRest(t: Tree): Tree = + if (in.token == AT) annotTypeRest(atPos(t.pos.start) { Annotated(annot(), t) }) + else t /** SimpleType ::= SimpleType TypeArgs * | SimpleType `#' Id @@ -1425,10 +1429,10 @@ object Parsers { else tree1 } - /** Annotation ::= `@' SimpleType {ArgumentExprs} + /** Annotation ::= `@' SimpleType {ParArgumentExprs} */ def annot() = - adjustStart(accept(AT)) { ensureApplied(argumentExprss(wrapNew(simpleType()))) } + adjustStart(accept(AT)) { ensureApplied(parArgumentExprss(wrapNew(simpleType()))) } def annotations(skipNewLines: Boolean = false): List[Tree] = { if (skipNewLines) newLineOptWhenFollowedBy(AT) @@ -1834,7 +1838,7 @@ object Parsers { /** ConstrApp ::= SimpleType {ParArgumentExprs} */ val constrApp = () => { - val t = simpleType() + val t = annotType() if (in.token == LPAREN) parArgumentExprss(wrapNew(t)) else t } diff --git a/src/dotty/tools/dotc/printing/PlainPrinter.scala b/src/dotty/tools/dotc/printing/PlainPrinter.scala index fb1c0fc74..12c94677f 100644 --- a/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -8,10 +8,11 @@ import StdNames.nme import ast.Trees._, ast._ import java.lang.Integer.toOctalString import config.Config.summarizeDepth +import typer.Mode import scala.annotation.switch class PlainPrinter(_ctx: Context) extends Printer { - protected[this] implicit def ctx: Context = _ctx + protected[this] implicit def ctx: Context = _ctx.fresh.addMode(Mode.Printing) protected def maxToTextRecursions = 100 @@ -169,6 +170,8 @@ class PlainPrinter(_ctx: Context) extends Printer { else TypeBounds.empty "(" ~ toText(tp.origin) ~ "?" ~ toText(bounds) ~ ")" } + case tp: LazyRef => + "LazyRef(" ~ toTextGlobal(tp.ref) ~ ")" case _ => tp.fallbackToText(this) } diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 11d451255..cc8f0bef8 100644 --- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -5,7 +5,7 @@ import core._ import Texts._, Types._, Flags._, Names._, Symbols._, NameOps._, Constants._ import TypeErasure.ErasedValueType import Contexts.Context, Scopes.Scope, Denotations._, SymDenotations._, Annotations.Annotation -import StdNames.nme +import StdNames.{nme, tpnme} import ast.{Trees, untpd, tpd} import typer.Namer import typer.ProtoTypes.{SelectionProto, ViewProto, FunProto, IgnoredProto, dummyTreeOfType} @@ -121,6 +121,14 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { } return (toTextLocal(tycon) ~ "[" ~ Text(args map argText, ", ") ~ "]").close } + if (tp.isSafeLambda) { + val (prefix, body, bindings) = extractApply(tp) + prefix match { + case prefix: TypeRef if prefix.symbol.isLambdaTrait && body.exists => + return typeLambdaText(prefix.symbol, body, bindings) + case _ => + } + } case tp: TypeRef => val hideType = tp.symbol is AliasPreferred if (hideType && !ctx.phase.erasedTypes && !tp.symbol.isCompleting) { @@ -159,6 +167,73 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { def blockText[T >: Untyped](trees: List[Tree[T]]): Text = "{" ~ toText(trees, "\n") ~ "}" + /** If type `tp` represents a potential type Lambda of the form + * + * parent { type Apply = body; argBindings? } + * + * split it into + + * - the `parent` + * - the simplified `body` + * - the bindings HK$ members, if there are any + * + * The body is simplified as follows + * - if it is a TypeAlias, follow it + * - replace all references to of the form <skolem>.HK$i by references + * without a prefix, because the latter print nicer. + * + */ + def extractApply(tp: Type): (Type, Type, List[(Name, Type)]) = tp.stripTypeVar match { + case tp @ RefinedType(parent, name) => + if (name == tpnme.Apply) { + // simplify arguments so that parameters just print HK$i and not + // LambdaI{...}.HK$i + val simplifyArgs = new TypeMap { + override def apply(tp: Type) = tp match { + case tp @ TypeRef(SkolemType(_), name) if name.isLambdaArgName => + TypeRef(NoPrefix, tp.symbol.asType) + case _ => + mapOver(tp) + } + } + (parent, simplifyArgs(tp.refinedInfo.followTypeAlias), Nil) + } else if (name.isLambdaArgName) { + val (prefix, body, argBindings) = extractApply(parent) + (prefix, body, (name, tp.refinedInfo) :: argBindings) + } else (tp, NoType, Nil) + case _ => + (tp, NoType, Nil) + } + + /** The text for a TypeLambda + * + * LambdaXYZ { type Apply = body'; bindings? } + * + * where + * @param lambdaCls The class symbol for `LambdaXYZ` + * @param body The simplified lambda body + * @param bindings The bindings of any HK$i arguments + * + * @return A text of the form + * + * [HK$0, ..., HK$n] => body + * + * possibly followed by bindings + * + * [HK$i = arg_i, ..., HK$k = arg_k] + */ + def typeLambdaText(lambdaCls: Symbol, body: Type, bindings: List[(Name, Type)]): Text = { + def lambdaParamText(tparam: Symbol): Text = { + varianceString(tparam) ~ nameString(tparam.name) + } + def lambdaText = changePrec(GlobalPrec) { + "[" ~ Text(lambdaCls.typeParams.map(lambdaParamText), ", ") ~ "] => " ~ toTextGlobal(body) + } + def bindingText(binding: (Name, Type)) = binding._1.toString ~ toTextGlobal(binding._2) + if (bindings.isEmpty) lambdaText + else atPrec(DotPrec)(lambdaText) ~ "[" ~ Text(bindings.map(bindingText), ", ") ~ "]" + } + override def toText[T >: Untyped](tree: Tree[T]): Text = controlled { import untpd.{modsDeco => _, _} diff --git a/src/dotty/tools/dotc/printing/Showable.scala b/src/dotty/tools/dotc/printing/Showable.scala index 550d80060..37de053cb 100644 --- a/src/dotty/tools/dotc/printing/Showable.scala +++ b/src/dotty/tools/dotc/printing/Showable.scala @@ -5,6 +5,7 @@ import core._ import Contexts._, Texts._, Decorators._ import config.Config.summarizeDepth +import scala.util.control.NonFatal trait Showable extends Any { @@ -20,7 +21,11 @@ trait Showable extends Any { def fallbackToText(printer: Printer): Text = toString /** The string representation of this showable element. */ - def show(implicit ctx: Context): String = toText(ctx.printer).show + def show(implicit ctx: Context): String = + try toText(ctx.printer).show + catch { + case NonFatal(ex) => s"[cannot display due to $ex, raw string = $toString]" + } /** The summarized string representation of this showable element. * Recursion depth is limited to some smallish value. Default is diff --git a/src/dotty/tools/dotc/reporting/Reporter.scala b/src/dotty/tools/dotc/reporting/Reporter.scala index 71a908397..7c5bab673 100644 --- a/src/dotty/tools/dotc/reporting/Reporter.scala +++ b/src/dotty/tools/dotc/reporting/Reporter.scala @@ -11,6 +11,7 @@ import config.Settings.Setting import config.Printers import java.lang.System.currentTimeMillis import typer.ErrorReporting.DiagnosticString +import typer.Mode object Reporter { @@ -73,9 +74,9 @@ trait Reporting { this: Context => /** For sending messages that are printed only if -verbose is set */ def inform(msg: => String, pos: SourcePosition = NoSourcePosition): Unit = - if (this.settings.verbose.value) echo(msg, pos) + if (this.settings.verbose.value) this.println(msg, pos) - def echo(msg: => String, pos: SourcePosition = NoSourcePosition): Unit = + def println(msg: => String, pos: SourcePosition = NoSourcePosition): Unit = reporter.report(new Info(msg, pos)) def deprecationWarning(msg: => String, pos: SourcePosition = NoSourcePosition): Unit = @@ -111,7 +112,7 @@ trait Reporting { this: Context => */ def log(msg: => String, pos: SourcePosition = NoSourcePosition): Unit = if (this.settings.log.value.containsPhase(phase)) - echo(s"[log ${ctx.phasesStack.reverse.mkString(" -> ")}] $msg", pos) + this.println(s"[log ${ctx.phasesStack.reverse.mkString(" -> ")}] $msg", pos) def debuglog(msg: => String): Unit = if (ctx.debug) log(msg) @@ -215,7 +216,7 @@ abstract class Reporter { } def report(d: Diagnostic)(implicit ctx: Context): Unit = if (!isHidden(d)) { - doReport(d) + doReport(d)(ctx.addMode(Mode.Printing)) d match { case d: ConditionalWarning if !d.enablingOption.value => unreportedWarnings(d.enablingOption.name) += 1 case d: Warning => warningCount += 1 @@ -231,10 +232,10 @@ abstract class Reporter { /** Print a summary */ def printSummary(implicit ctx: Context): Unit = { - if (warningCount > 0) ctx.echo(countString(warningCount, "warning") + " found") - if (errorCount > 0) ctx.echo(countString(errorCount, "error") + " found") + if (warningCount > 0) ctx.println(countString(warningCount, "warning") + " found") + if (errorCount > 0) ctx.println(countString(errorCount, "error") + " found") for ((settingName, count) <- unreportedWarnings) - ctx.echo(s"there were $count ${settingName.tail} warning(s); re-run with $settingName for details") + ctx.println(s"there were $count ${settingName.tail} warning(s); re-run with $settingName for details") } /** Returns a string meaning "n elements". */ @@ -248,7 +249,7 @@ abstract class Reporter { } /** Should this diagnostic not be reported at all? */ - def isHidden(d: Diagnostic)(implicit ctx: Context): Boolean = false + def isHidden(d: Diagnostic)(implicit ctx: Context): Boolean = ctx.mode.is(Mode.Printing) /** Does this reporter contain not yet reported errors or warnings? */ def hasPending: Boolean = false diff --git a/src/dotty/tools/dotc/transform/PatternMatcher.scala b/src/dotty/tools/dotc/transform/PatternMatcher.scala index d665aa0c5..507dbb0ce 100644 --- a/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -21,6 +21,7 @@ import ast.Trees._ import Applications._ import TypeApplications._ import SymUtils._, core.NameOps._ +import typer.Mode import dotty.tools.dotc.util.Positions.Position import dotty.tools.dotc.core.Decorators._ @@ -464,8 +465,9 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans // all potentially stored subpat binders val potentiallyStoredBinders = stored.unzip._1.toSet // compute intersection of all symbols in the tree `in` and all potentially stored subpat binders - new DeepFolder[Unit]((x: Unit, t:Tree) => + def computeBinders(implicit ctx: Context) = new DeepFolder[Unit]((x: Unit, t:Tree) => if (potentiallyStoredBinders(t.symbol)) usedBinders += t.symbol).apply((), in) + computeBinders(ctx.addMode(Mode.FutureDefsOK)) // trigged a NotDefinedHere on $outer when compiler dotc/printing if (usedBinders.isEmpty) in else { diff --git a/src/dotty/tools/dotc/typer/Mode.scala b/src/dotty/tools/dotc/typer/Mode.scala index 997741819..8889cf604 100644 --- a/src/dotty/tools/dotc/typer/Mode.scala +++ b/src/dotty/tools/dotc/typer/Mode.scala @@ -63,5 +63,10 @@ object Mode { */ val AllowDependentFunctions = newMode(9, "AllowDependentFunctions") + /** We are currently printing something: avoid to produce more logs about + * the printing + */ + val Printing = newMode(10, "Printing") + val PatternOrType = Pattern | Type } diff --git a/tests/pos/Iterable.scala b/tests/pos/Iterable.scala new file mode 100644 index 000000000..715667e7a --- /dev/null +++ b/tests/pos/Iterable.scala @@ -0,0 +1,52 @@ +package dotty.collections +package immutable + +import annotation.unchecked.uncheckedVariance + +trait Collection[+CC[X] <: Collection[CC, X], T] { + def companion: CollectionCompanion[CC] +} + +trait Iterable[T] extends Collection[Iterable, T] { + def iterator: Iterator[T] + override def companion: IterableCompanion[Iterable] = Iterable +} + +trait Seq[T] extends Iterable[T] with Collection[Seq, T] { + def apply(x: Int): T + override def companion: IterableCompanion[Seq] = Seq +} + +abstract class CollectionCompanion[+CC[X] <: Collection[CC, X]] + +trait IterableImpls[CC[X]] { + def fromIterator[T](it: Iterator[T]): CC[T] + def toIterator[T](xs: CC[T]): Iterator[T] + def map[T, U](xs: CC[T], f: T => U): CC[U] = + fromIterator(toIterator(xs).map(f)) + def filter[T](xs: CC[T], p: T => Boolean): CC[T] = + fromIterator(toIterator(xs).filter(p)) + def flatMap[T, U](xs: CC[T], f: T => TraversableOnce[U]): CC[U] = + fromIterator(toIterator(xs).flatMap(f)) +} + +abstract class IterableCompanion[+CC[X] <: Iterable[X] with Collection[CC, X]] +extends CollectionCompanion[CC] with IterableImpls[CC] @uncheckedVariance { + def toIterator[T](xs: CC[T] @uncheckedVariance) = xs.iterator + implicit def transformOps[T](xs: CC[T] @uncheckedVariance): TransformOps[CC, T] = new TransformOps[CC, T](xs) +} + +class TransformOps[+CC[X] <: Iterable[X] with Collection[CC, X], T] (val xs: CC[T]) extends AnyVal { + def companion[T](xs: CC[T] @uncheckedVariance): IterableCompanion[CC] = xs.companion.asInstanceOf + def map[U](f: T => U): CC[U] = companion(xs).map(xs, f) + def filter(p: T => Boolean): CC[T] = companion(xs).filter(xs, p) + def flatMap[U](f: T => TraversableOnce[U]): CC[U] = companion(xs).flatMap(xs, f) +} + +object Iterable extends IterableCompanion[Iterable] { + def fromIterator[T](it: Iterator[T]): Iterable[T] = ??? +} +object Seq extends IterableCompanion[Seq] { + def fromIterator[T](it: Iterator[T]): Seq[T] = ??? +} + diff --git a/tests/pos/IterableSelfRec.scala b/tests/pos/IterableSelfRec.scala new file mode 100644 index 000000000..bba7a82d2 --- /dev/null +++ b/tests/pos/IterableSelfRec.scala @@ -0,0 +1,52 @@ +package dotty.collection +package immutable + +import annotation.unchecked.uncheckedVariance + +trait Collection[T] { self => + type This <: Collection { type This <: self.This } + def companion: CollectionCompanion[This] +} + +trait Iterable[T] extends Collection[T] { self => + type This <: Iterable { type This <: self.This } + override def companion: IterableCompanion[This] = Iterable.asInstanceOf + + def iterator: Iterator[T] +} + +trait Seq[T] extends Iterable[T] { self => + type This <: Seq { type This <: self.This } + override def companion: IterableCompanion[This] = Seq.asInstanceOf + + def apply(x: Int): T +} + +abstract class CollectionCompanion[+CC <: Collection { type This <: CC }] + +abstract class IterableCompanion[+CC <: Iterable { type This <: CC }] extends CollectionCompanion[CC] { + def fromIterator[T](it: Iterator[T]): CC[T] + def map[T, U](xs: Iterable[T], f: T => U): CC[U] = + fromIterator(xs.iterator.map(f)) + def filter[T](xs: Iterable[T], p: T => Boolean): CC[T] = + fromIterator(xs.iterator.filter(p)) + def flatMap[T, U](xs: Iterable[T], f: T => TraversableOnce[U]): CC[U] = + fromIterator(xs.iterator.flatMap(f)) + + implicit def transformOps[T](xs: CC[T] @uncheckedVariance): TransformOps[CC, T] = ??? // new TransformOps[CC, T](xs) +} + +class TransformOps[+CC <: Iterable { type This <: CC }, T] (val xs: CC[T]) extends AnyVal { + def companion[T](xs: CC[T] @uncheckedVariance): IterableCompanion[CC] = xs.companion + def map[U](f: T => U): CC[U] = companion(xs).map(xs, f) + def filter(p: T => Boolean): CC[T] = companion(xs).filter(xs, p) + def flatMap[U](f: T => TraversableOnce[U]): CC[U] = companion(xs).flatMap(xs, f) +} + +object Iterable extends IterableCompanion[Iterable] { + def fromIterator[T](it: Iterator[T]): Iterable[T] = ??? +} +object Seq extends IterableCompanion[Seq] { + def fromIterator[T](it: Iterator[T]): Seq[T] = ??? +} + diff --git a/tests/pos/annot.scala b/tests/pos/annot.scala index c3a17ff1d..e6e4f8051 100644 --- a/tests/pos/annot.scala +++ b/tests/pos/annot.scala @@ -1,7 +1,10 @@ import java.beans.Transient +import annotation.unchecked.uncheckedVariance class Test { +// testing combinations of annotation syntax + @SuppressWarnings(Array("hi")) def foo() = ??? // evalutation of annotation on type cannot be deferred as requires implicit resolution(only generic Array$.apply applies here) @SuppressWarnings(Array("hi", "foo")) def foo2() = ??? //can be deferred as there is a non-generic method @@ -11,5 +14,15 @@ class Test { @Transient(false) def bar = ??? @Transient() def baz = ??? + +// testing annotations in types + + class A + trait B + + val x: A @uncheckedVariance with B @uncheckedVariance = ??? + + class C extends A @uncheckedVariance () with B @uncheckedVariance { val x = 10 } + } |