From 3f8b83adb78e49fe5b6575f4b8f3061f5082b017 Mon Sep 17 00:00:00 2001 From: olsdavis Date: Wed, 23 Feb 2022 09:55:03 +0000 Subject: [PATCH 0001/1244] Implementing lazy vals - Implements a propotype of the new lazy vals scheme Fix/Fixing/Fixes/Close/Closing/Refs #7140 --- .../dotty/tools/dotc/transform/LazyVals.scala | 363 +++-- library/src/scala/runtime/LazyVals.scala | 65 +- vscode-dotty/package-lock.json | 1417 ++++++++++++++++- vscode-dotty/package.json | 2 +- 4 files changed, 1663 insertions(+), 184 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala index aabf8cf9a680..6126bc9b3e0b 100644 --- a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala +++ b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala @@ -23,9 +23,10 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { import LazyVals._ import tpd._ - /** this map contains mutable state of transformation: OffsetDefs to be appended to companion object definitions, - * and number of bits currently used */ - class OffsetInfo(var defs: List[Tree], var ord:Int) + /** + * The map contains the list of the offset trees. + */ + class OffsetInfo(var defs: List[Tree]) private val appendOffsetDefs = mutable.Map.empty[Symbol, OffsetInfo] override def phaseName: String = LazyVals.name @@ -52,6 +53,16 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { else nullables.toList } + private def initBlock(stats: List[Tree])(using Context): Block = stats match + case Nil => throw new IllegalArgumentException("trying to create an empty Block") + case x :: Nil => Block(List(x), EmptyTree) + case x :: xs => Block(stats.init, stats.last) + + private def needsBoxing(tp: Type)(using Context): Boolean = tp != NoType && tp != defn.UnitType && tp.classSymbol.isPrimitiveValueClass + + private def boxIfCan(tp: Type)(using Context): Type = + assert(needsBoxing(tp)) + defn.boxedType(tp) override def prepareForUnit(tree: Tree)(using Context): Context = { if (lazyValNullables == null) @@ -62,7 +73,6 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { override def transformDefDef(tree: DefDef)(using Context): Tree = transformLazyVal(tree) - override def transformValDef(tree: ValDef)(using Context): Tree = transformLazyVal(tree) @@ -101,7 +111,6 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { } } - /** Append offset fields to companion objects */ override def transformTemplate(template: Template)(using Context): Tree = { @@ -115,16 +124,15 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { } } - private def addInFront(prefix: List[Tree], stats: List[Tree]) = stats match { case first :: rest if isSuperConstrCall(first) => first :: prefix ::: rest case _ => prefix ::: stats } - /** Make an eager val that would implement synthetic module. - * Eager val ensures thread safety and has less code generated. - * - */ + /** + * Make an eager val that would implement synthetic module. + * Eager val ensures thread safety and has less code generated. + */ def transformSyntheticModule(tree: ValOrDefDef)(using Context): Thicket = { val sym = tree.symbol val holderSymbol = newSymbol(sym.owner, LazyLocalName.fresh(sym.asTerm.name), @@ -134,7 +142,8 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { Thicket(field, getter) } - /** Desugar a local `lazy val x: Int = ` into: + /** + * Desugar a local `lazy val x: Int = ` into: * * ``` * val x$lzy = new scala.runtime.LazyInt() @@ -186,7 +195,6 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { Thicket(holderTree, initTree, accessor) } - override def transformStats(trees: List[tpd.Tree])(using Context): List[Tree] = { // backend requires field usage to be after field definition // need to bring containers to start of method @@ -274,168 +282,212 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { } } - /** Create a threadsafe lazy accessor equivalent to such code - * ``` - * def methodSymbol(): Int = { - * while (true) { - * val flag = LazyVals.get(this, bitmap_offset) - * val state = LazyVals.STATE(flag, ) - * - * if (state == ) { - * return value_0 - * } else if (state == ) { - * if (LazyVals.CAS(this, bitmap_offset, flag, , )) { - * try { - * val result = - * value_0 = result - * nullable = null - * LazyVals.setFlag(this, bitmap_offset, , ) - * return result - * } - * catch { - * case ex => - * LazyVals.setFlag(this, bitmap_offset, , ) - * throw ex - * } - * } - * } else /* if (state == || state == ) */ { - * LazyVals.wait4Notification(this, bitmap_offset, flag, ) - * } - * } - * } - * ``` - */ + /** + * Create a threadsafe lazy accessor equivalent to the following code: + * ``` + * private @volatile var _x: AnyRef = null + * @tailrec def x: A = + * _x match + * case current: A => + * current + * case null => + * if CAS(_x, null, Evaluating) then + * var result: AnyRef = null // here, we need `AnyRef` to possibly assign `NULL` + * try + * result = rhs + * nullable = null // if the field is nullable; see `CollectNullableFields` + * if result == null then result = NULL // drop if A is non-nullable + * finally + * if !CAS(_x, Evaluating, result) then + * val lock = _x.asInstanceOf[Waiting] + * CAS(_x, lock, result) + * lock.release() + * x + * case Evaluating => + * CAS(_x, Evaluating, new Waiting) + * x + * case current: Waiting => + * current.awaitRelease() + * x + * case NULL => null + * ``` + * Where `Evaluating` and `NULL` are represented by `object`s and `Waiting` by a class that + * allows awaiting the completion of the evaluation. Note that since tail-recursive + * functions are transformed *before* lazy-vals, this implementation directly implements + * the resulting loop. `PatternMatcher` coming before `LazyVals`, the pattern matching block + * is implemented using if-s. That is: + * + * ``` + * private @volatile var _x: AnyRef = null + * def x: A = + * while true do + * val current: AnyRef = _x + * if current == null then + * if CAS(_x, null, Evaluating) then + * var result: AnyRef = null + * try + * result = rhs + * nullable = null + * if result == null then result = NULL + * finally + * if !CAS(_x, Evaluating, result) then + * val lock = _x.asInstanceOf[Waiting] + * CAS(_x, lock, result) + * lock.release() + * else + * if current.isInstanceOf[A] then + * current.asInstanceOf[A] + * else if current.isInstanceOf[NULL] then + * null + * else if current.isInstanceOf[Waiting] then + * current.asInstanceOf[Waiting].awaitRelease() + * else // `current` is Evaluating + * CAS(current, Evaluating, new Waiting) + * end while + * ``` + * + * @param methodSymbol the symbol of the new method + * @param claz the class containing this lazy val field + * @param target the target synthetic field + * @param rhs the right-hand side expression of the lazy val + * @param tp the type of the lazy val + * @param offset the offset of the field in the bitmap + * @param getFlag a flag for the volatile get function + * @param objCasFlag a flag for the CAS function operating on objects + * @param waiting a reference to the `Waiting` runtime class + * @param evaluating a reference to the `Evaluating` runtime object + * @param nullValued a reference to the `NULL` runtime object + */ def mkThreadSafeDef(methodSymbol: TermSymbol, claz: ClassSymbol, - ord: Int, target: Symbol, rhs: Tree, tp: Type, offset: Tree, - getFlag: Tree, - stateMask: Tree, - casFlag: Tree, - setFlagState: Tree, - waitOnLock: Tree)(using Context): DefDef = { - val initState = Literal(Constant(0)) - val computeState = Literal(Constant(1)) - val computedState = Literal(Constant(3)) - - val thiz = This(claz) - val fieldId = Literal(Constant(ord)) - - val flagSymbol = newSymbol(methodSymbol, lazyNme.flag, Synthetic, defn.LongType) - val flagDef = ValDef(flagSymbol, getFlag.appliedTo(thiz, offset)) - val flagRef = ref(flagSymbol) - - val stateSymbol = newSymbol(methodSymbol, lazyNme.state, Synthetic, defn.LongType) - val stateDef = ValDef(stateSymbol, stateMask.appliedTo(ref(flagSymbol), Literal(Constant(ord)))) - val stateRef = ref(stateSymbol) - - val compute = { - val resultSymbol = newSymbol(methodSymbol, lazyNme.result, Synthetic, tp) - val resultRef = ref(resultSymbol) - val stats = ( - ValDef(resultSymbol, rhs) :: - ref(target).becomes(resultRef) :: - (nullOut(nullableFor(methodSymbol)) :+ - setFlagState.appliedTo(thiz, offset, computedState, fieldId)) - ) - Block(stats, Return(resultRef, methodSymbol)) - } - - val retryCase = { - val caseSymbol = newSymbol(methodSymbol, nme.DEFAULT_EXCEPTION_NAME, Synthetic | Case, defn.ThrowableType) - val triggerRetry = setFlagState.appliedTo(thiz, offset, initState, fieldId) - CaseDef( - Bind(caseSymbol, ref(caseSymbol)), - EmptyTree, - Block(List(triggerRetry), Throw(ref(caseSymbol))) + objCasFlag: Tree, + waiting: Tree, + evaluating: Tree, + nullValued: Tree, + thiz: Tree)(using Context): DefDef = { + val discardSymb = newSymbol(methodSymbol, lazyNme.discard, Method | Synthetic, MethodType(Nil)(_ => Nil, _ => defn.UnitType)) + val discardDef = DefDef(discardSymb, initBlock( + objCasFlag.appliedTo(thiz, offset, evaluating, Select(New(waiting), StdNames.nme.CONSTRUCTOR).ensureApplied) + :: Return(unitLiteral, discardSymb) :: Nil)) + // if observed a null value + val unevaluated = { + // var res: AnyRef + val resSymb = newSymbol(methodSymbol, lazyNme.result, Synthetic | Mutable, defn.ObjectType) + // releasing block in finally + val lockRel = { + val lockSymb = newSymbol(methodSymbol, lazyNme.lock, Synthetic, waiting.typeOpt) + initBlock(ValDef(lockSymb, ref(target).cast(waiting.typeOpt)) + :: objCasFlag.appliedTo(thiz, offset, ref(lockSymb), ref(resSymb)) + :: ref(lockSymb).select(lazyNme.RLazyVals.waitingRelease).ensureApplied :: Nil) + } + // finally block + val fin = If( + objCasFlag.appliedTo(thiz, offset, evaluating, ref(resSymb)).equal(Literal(Constant(false))), + lockRel, + EmptyTree + ).withType(defn.UnitType) + // entire try block + val evaluate = Try( + initBlock( + Assign(ref(resSymb), if needsBoxing(tp) && rhs != EmptyTree then rhs.ensureConforms(boxIfCan(tp)) else rhs) // try result = rhs + :: nullOut(nullableFor(methodSymbol)) + ::: If(ref(resSymb).equal(nullLiteral), Assign(ref(resSymb), nullValued), EmptyTree).withType(defn.UnitType) // if result == null then result = NULL + :: Nil + ), + Nil, + fin ) + // if CAS(...) + If( + objCasFlag.appliedTo(thiz, offset, nullLiteral, evaluating), + initBlock(ValDef(resSymb, nullLiteral) // var result: AnyRef = null + :: evaluate // try ... finally ... + :: Nil), + EmptyTree + ).withType(defn.UnitType) } - - val initialize = If( - casFlag.appliedTo(thiz, offset, flagRef, computeState, fieldId), - Try(compute, List(retryCase), EmptyTree), - unitLiteral - ) - - val condition = If( - stateRef.equal(computedState), - Return(ref(target), methodSymbol), + val current = newSymbol(methodSymbol, lazyNme.current, Synthetic, defn.ObjectType) + val ifNotNull = If( - stateRef.equal(initState), - initialize, - waitOnLock.appliedTo(thiz, offset, flagRef, fieldId) + ref(current).select(defn.Any_isInstanceOf).appliedToType(if needsBoxing(tp) then boxIfCan(tp) else tp), + Return(ref(current).ensureConforms(tp), methodSymbol), + // not an A + If( + ref(current).select(defn.Any_isInstanceOf).appliedToTypeTree(nullValued), + Return(defaultValue(tp), methodSymbol), + // not a NULL + If( + ref(current).select(defn.Any_isInstanceOf).appliedToTypeTree(waiting), + ref(current).select(defn.Any_asInstanceOf).appliedToTypeTree(waiting).select(lazyNme.RLazyVals.waitingAwaitRelease).ensureApplied, + // not a Waiting, then is an Evaluating + ref(discardSymb).ensureApplied + ) + ) ) - ) - - val loop = WhileDo(EmptyTree, Block(List(flagDef, stateDef), condition)) - DefDef(methodSymbol, loop) + val body = initBlock(ValDef(current, ref(target)) :: If(ref(current).equal(nullLiteral), unevaluated, ifNotNull) :: Nil) + val mainLoop = WhileDo(EmptyTree, body) // becomes: while (true) do { body } + val ret = DefDef(methodSymbol, initBlock(discardDef :: mainLoop :: Nil)) + ret } def transformMemberDefThreadSafe(x: ValOrDefDef)(using Context): Thicket = { assert(!(x.symbol is Mutable)) - + import dotty.tools.dotc.core.Types._ + import dotty.tools.dotc.core.Flags._ + + val runtimeModule = "scala.runtime.LazyVals" val tpe = x.tpe.widen.resultType.widen val claz = x.symbol.owner.asClass val thizClass = Literal(Constant(claz.info)) - val helperModule = requiredModule("scala.runtime.LazyVals") + val helperModule = requiredModule(runtimeModule) val getOffset = Select(ref(helperModule), lazyNme.RLazyVals.getOffset) var offsetSymbol: TermSymbol = null - var flag: Tree = EmptyTree - var ord = 0 def offsetName(id: Int) = s"${StdNames.nme.LAZY_FIELD_OFFSET}${if (x.symbol.owner.is(Module)) "_m_" else ""}$id".toTermName - // compute or create appropriate offsetSymbol, bitmap and bits used by current ValDef - appendOffsetDefs.get(claz) match { + val containerName = LazyLocalName.fresh(x.name.asTermName) + val containerSymbol = newSymbol(claz, containerName, containerFlags, defn.ObjectType).enteredAfter(this) + containerSymbol.addAnnotation(Annotation(defn.VolatileAnnot)) // private @volatile var _x: AnyRef + val stat = x.symbol.isStatic + if stat then + containerSymbol.setFlag(JavaStatic) + val containerTree = ValDef(containerSymbol, nullLiteral) + def staticOrFieldOff: Tree = getOffset.appliedTo(thizClass, Literal(Constant(containerName.toString))) + + // create an offset for this lazy val + appendOffsetDefs.get(claz) match case Some(info) => - val flagsPerLong = (64 / scala.runtime.LazyVals.BITS_PER_LAZY_VAL).toInt - info.ord += 1 - ord = info.ord % flagsPerLong - val id = info.ord / flagsPerLong - val offsetById = offsetName(id) - if (ord != 0) // there are unused bits in already existing flag - offsetSymbol = claz.info.decl(offsetById) - .suchThat(sym => sym.is(Synthetic) && sym.isTerm) - .symbol.asTerm - else { // need to create a new flag - offsetSymbol = newSymbol(claz, offsetById, Synthetic, defn.LongType).enteredAfter(this) - offsetSymbol.addAnnotation(Annotation(defn.ScalaStaticAnnot)) - val flagName = LazyBitMapName.fresh(id.toString.toTermName) - val flagSymbol = newSymbol(claz, flagName, containerFlags, defn.LongType).enteredAfter(this) - flag = ValDef(flagSymbol, Literal(Constant(0L))) - val offsetTree = ValDef(offsetSymbol, getOffset.appliedTo(thizClass, Literal(Constant(flagName.toString)))) - info.defs = offsetTree :: info.defs - } - + offsetSymbol = newSymbol(claz, offsetName(info.defs.size), Synthetic, defn.LongType).enteredAfter(this) + offsetSymbol.addAnnotation(Annotation(defn.ScalaStaticAnnot)) + val offsetTree = ValDef(offsetSymbol, staticOrFieldOff) + info.defs = offsetTree :: info.defs case None => offsetSymbol = newSymbol(claz, offsetName(0), Synthetic, defn.LongType).enteredAfter(this) offsetSymbol.addAnnotation(Annotation(defn.ScalaStaticAnnot)) - val flagName = LazyBitMapName.fresh("0".toTermName) - val flagSymbol = newSymbol(claz, flagName, containerFlags, defn.LongType).enteredAfter(this) - flag = ValDef(flagSymbol, Literal(Constant(0L))) - val offsetTree = ValDef(offsetSymbol, getOffset.appliedTo(thizClass, Literal(Constant(flagName.toString)))) - appendOffsetDefs += (claz -> new OffsetInfo(List(offsetTree), ord)) - } - - val containerName = LazyLocalName.fresh(x.name.asTermName) - val containerSymbol = newSymbol(claz, containerName, x.symbol.flags &~ containerFlagsMask | containerFlags, tpe, coord = x.symbol.coord).enteredAfter(this) - - val containerTree = ValDef(containerSymbol, defaultValue(tpe)) - - val offset = ref(offsetSymbol) - val getFlag = Select(ref(helperModule), lazyNme.RLazyVals.get) - val setFlag = Select(ref(helperModule), lazyNme.RLazyVals.setFlag) - val wait = Select(ref(helperModule), lazyNme.RLazyVals.wait4Notification) - val state = Select(ref(helperModule), lazyNme.RLazyVals.state) - val cas = Select(ref(helperModule), lazyNme.RLazyVals.cas) - - val accessor = mkThreadSafeDef(x.symbol.asTerm, claz, ord, containerSymbol, x.rhs, tpe, offset, getFlag, state, cas, setFlag, wait) - if (flag eq EmptyTree) - Thicket(containerTree, accessor) - else Thicket(containerTree, flag, accessor) + val offsetTree = ValDef(offsetSymbol, staticOrFieldOff) + appendOffsetDefs += (claz -> new OffsetInfo(List(offsetTree))) + + val waiting = requiredClass(s"$runtimeModule.${lazyNme.RLazyVals.waiting}") + val evaluating = Select(ref(helperModule), lazyNme.RLazyVals.evaluating) + val nullValued = Select(ref(helperModule), lazyNme.RLazyVals.nullValued) + val objCas = Select(ref(helperModule), lazyNme.RLazyVals.objCas) + + val offset = ref(offsetSymbol) + + val swapOver = + if stat then + tpd.clsOf(x.symbol.owner.typeRef) + else + This(claz) + + val methodSymbol = x.symbol.asTerm + val accessor = mkThreadSafeDef(methodSymbol, claz, containerSymbol, x.rhs, tpe, offset, objCas, + ref(waiting), evaluating, nullValued, swapOver) + Thicket(containerTree, accessor) } } @@ -447,12 +499,14 @@ object LazyVals { import Names.TermName object RLazyVals { import scala.runtime.LazyVals.{Names => N} - val get: TermName = N.get.toTermName - val setFlag: TermName = N.setFlag.toTermName - val wait4Notification: TermName = N.wait4Notification.toTermName - val state: TermName = N.state.toTermName - val cas: TermName = N.cas.toTermName + val waiting: TermName = N.waiting.toTermName + val waitingAwaitRelease: TermName = N.waitingAwaitRelease.toTermName + val waitingRelease: TermName = N.waitingRelease.toTermName + val evaluating: TermName = N.evaluating.toTermName + val nullValued: TermName = N.nullValued.toTermName + val objCas: TermName = N.objCas.toTermName val getOffset: TermName = N.getOffset.toTermName + val getStaticOffset: TermName = N.getStaticOffset.toTermName } val flag: TermName = "flag".toTermName val state: TermName = "state".toTermName @@ -461,5 +515,8 @@ object LazyVals { val initialized: TermName = "initialized".toTermName val initialize: TermName = "initialize".toTermName val retry: TermName = "retry".toTermName + val current: TermName = "current".toTermName + val lock: TermName = "lock".toTermName + val discard: TermName = "discard".toTermName } } diff --git a/library/src/scala/runtime/LazyVals.scala b/library/src/scala/runtime/LazyVals.scala index 85ca4f5cb3a0..0c1a6dd421e6 100644 --- a/library/src/scala/runtime/LazyVals.scala +++ b/library/src/scala/runtime/LazyVals.scala @@ -1,5 +1,7 @@ package scala.runtime +import java.lang.reflect.Modifier + /** * Helper methods used in thread-safe lazy vals. */ @@ -22,6 +24,7 @@ object LazyVals { val processors = java.lang.Runtime.getRuntime.nn.availableProcessors() 8 * processors * processors } + private[this] val monitors: Array[Object] = Array.tabulate(base)(_ => new Object) @@ -37,6 +40,41 @@ object LazyVals { /* ------------- Start of public API ------------- */ + /** + * Used to indicate the state of a lazy val that is being + * evaluated and of which other threads await the result. + */ + final class Waiting: + private var done = false + + /** + * Wakes up waiting threads. Called on completion of the evaluation + * of lazy val's right-hand side. + */ + def release(): Unit = synchronized { + done = true + notifyAll() + } + + /** + * Awaits the completion of the evaluation of lazy val's right-hand side. + */ + def awaitRelease(): Unit = synchronized { + while !done do wait() + } + + /** + * Used to indicate the state of a lazy val that is currently being + * evaluated with no other thread awaiting its result. + */ + object Evaluating + + /** + * Used to indicate the state of a lazy val that has been evaluated to + * `null`. + */ + object NULL + final val BITS_PER_LAZY_VAL = 2L def STATE(cur: Long, ord: Int): Long = { @@ -54,6 +92,12 @@ object LazyVals { unsafe.compareAndSwapLong(t, offset, e, n) } + def objCAS(t: Object, offset: Long, exp: Object, n: Object): Boolean = { + if (debug) + println(s"objCAS($t, $exp, $n)") + unsafe.compareAndSwapObject(t, offset, exp, n) + } + def setFlag(t: Object, offset: Long, v: Int, ord: Int): Unit = { if (debug) println(s"setFlag($t, $offset, $v, $ord)") @@ -100,18 +144,35 @@ object LazyVals { } def getOffset(clz: Class[_], name: String): Long = { - val r = unsafe.objectFieldOffset(clz.getDeclaredField(name)) if (debug) - println(s"getOffset($clz, $name) = $r") + clz.getDeclaredFields.foreach(println(_)) + val field = clz.getDeclaredField(name) + if java.lang.reflect.Modifier.isStatic(field.getModifiers()) then + unsafe.staticFieldOffset(field) + else + unsafe.objectFieldOffset(field) + } + + def getStaticOffset(clz: Class[_], name: String): Long = { + val r = unsafe.staticFieldOffset(clz.getDeclaredField(name)) + if (debug) + println(s"getStaticOffset($clz, $name) = $r") r } object Names { + final val waiting = "Waiting" + final val evaluating = "Evaluating" + final val nullValued = "NULL" + final val waitingAwaitRelease = "awaitRelease" + final val waitingRelease = "release" final val state = "STATE" final val cas = "CAS" + final val objCas = "objCAS" final val setFlag = "setFlag" final val wait4Notification = "wait4Notification" final val get = "get" final val getOffset = "getOffset" + final val getStaticOffset = "getStaticOffset" } } diff --git a/vscode-dotty/package-lock.json b/vscode-dotty/package-lock.json index 22e232900f01..e1c1e9906ad7 100644 --- a/vscode-dotty/package-lock.json +++ b/vscode-dotty/package-lock.json @@ -1,9 +1,1345 @@ { "name": "dotty", "version": "0.1.17-snapshot", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "dotty", + "version": "0.1.17-snapshot", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "archiver": "^3.1.1", + "compare-versions": "^3.5.1", + "promisify-child-process": "^2.1.2", + "request": "^2.88.0", + "vscode-jsonrpc": "4.0.0", + "vscode-languageclient": "^5.2.1", + "vscode-languageserver": "^5.2.1", + "ws": "^6.2.1" + }, + "devDependencies": { + "@types/archiver": "^2.1.3", + "@types/compare-versions": "^3.0.0", + "@types/mocha": "^5.2.7", + "@types/node": "^10.14.18", + "@types/request": "^2.48.3", + "@types/ws": "^6.0.3", + "typescript": "^3.6.3", + "vscode": "^1.1.37" + }, + "engines": { + "vscode": "^1.30.0" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/archiver": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-2.1.3.tgz", + "integrity": "sha512-x37dj6VvV8jArjvqvZP+qz5+24qOwgFesLMvn98uNz8qebjCg+uteqquRf9mqaxxhcM7S1vPl4YFhBs2/abcFQ==", + "dev": true, + "dependencies": { + "@types/glob": "*" + } + }, + "node_modules/@types/caseless": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", + "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==", + "dev": true + }, + "node_modules/@types/compare-versions": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/compare-versions/-/compare-versions-3.0.0.tgz", + "integrity": "sha512-HNXtUQQuW3ThO9DVfTNbdvClVr+8AZlNNa2pxk5qtEvObnT27qh0DdQXTN4h5PuTTGinxwXkRKXsllJxuAzGPw==", + "dev": true + }, + "node_modules/@types/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", + "dev": true + }, + "node_modules/@types/glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", + "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", + "dev": true, + "dependencies": { + "@types/events": "*", + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "node_modules/@types/mocha": { + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", + "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "10.14.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.18.tgz", + "integrity": "sha512-ryO3Q3++yZC/+b8j8BdKd/dn9JlzlHBPdm80656xwYUdmPkpTGTjkAdt6BByiNupGPE8w0FhBgvYy/fX9hRNGQ==", + "dev": true + }, + "node_modules/@types/request": { + "version": "2.48.3", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.3.tgz", + "integrity": "sha512-3Wo2jNYwqgXcIz/rrq18AdOZUQB8cQ34CXZo+LUwPJNpvRAL86+Kc2wwI8mqpz9Cr1V+enIox5v+WZhy/p3h8w==", + "dev": true, + "dependencies": { + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" + } + }, + "node_modules/@types/request/node_modules/form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/@types/tough-cookie": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.5.tgz", + "integrity": "sha512-SCcK7mvGi3+ZNz833RRjFIxrn4gI1PPR3NtuIS+6vMkvmsGjosqTJwRt5bAEFLRz+wtJMWv8+uOnZf2hi2QXTg==", + "dev": true + }, + "node_modules/@types/ws": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-6.0.3.tgz", + "integrity": "sha512-yBTM0P05Tx9iXGq00BbJPo37ox68R5vaGTXivs6RGh/BQ6QP5zqZDGWdAO6JbRE/iR1l80xeGAwCQS2nMV9S/w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dependencies": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "node_modules/archiver": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-3.1.1.tgz", + "integrity": "sha512-5Hxxcig7gw5Jod/8Gq0OneVgLYET+oNHcxgWItq4TbhOzRLKNAFUb9edAftiMKXvXfCB0vbGrJdZDNq0dWMsxg==", + "dependencies": { + "archiver-utils": "^2.1.0", + "async": "^2.6.3", + "buffer-crc32": "^0.2.1", + "glob": "^7.1.4", + "readable-stream": "^3.4.0", + "tar-stream": "^2.1.0", + "zip-stream": "^2.1.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "dependencies": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver-utils/node_modules/readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "node_modules/base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/bl": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-3.0.0.tgz", + "integrity": "sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A==", + "dependencies": { + "readable-stream": "^3.0.1" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/buffer": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz", + "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/combined-stream": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, + "node_modules/compare-versions": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.5.1.tgz", + "integrity": "sha512-9fGPIB7C6AyM18CJJBHt5EnCZDG3oiTJYy0NjfIAGjKpzv0tkxWko7TNQHF5ymqm7IH03tqmeuBxtvD+Izh6mg==" + }, + "node_modules/compress-commons": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-2.1.1.tgz", + "integrity": "sha512-eVw6n7CnEMFzc3duyFVrQEuY1BlHR3rYsSztyG32ibGMW722i3C6IizEGMFmfMU+A+fALvBIwxN3czffTcdA+Q==", + "dependencies": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^3.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^2.3.6" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/compress-commons/node_modules/readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "node_modules/crc": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", + "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", + "dependencies": { + "buffer": "^5.1.0" + } + }, + "node_modules/crc32-stream": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-3.0.1.tgz", + "integrity": "sha512-mctvpXlbzsvK+6z8kJwSJ5crm7yBwrQMTybJzMw1O4lLGJqjlDCXY2Zw7KheiA6XBEcBmfLx1D88mjRGVJtY9w==", + "dependencies": { + "crc": "^3.4.4", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">= 6.9.0" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "dependencies": { + "es6-promise": "^4.0.3" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", + "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==" + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "engines": { + "node": ">=4.x" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", + "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", + "dependencies": { + "ajv": "^5.3.0", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "dev": true, + "dependencies": { + "agent-base": "4", + "debug": "3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/https-proxy-agent": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz", + "integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==", + "dev": true, + "dependencies": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "node_modules/json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "node_modules/json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "node_modules/jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "node_modules/lazystream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", + "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" + }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=" + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "node_modules/lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=" + }, + "node_modules/mime-db": { + "version": "1.37.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", + "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.21", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", + "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", + "dependencies": { + "mime-db": "~1.37.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "node_modules/mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "dependencies": { + "minimist": "0.0.8" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mocha": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", + "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "dev": true, + "dependencies": { + "browser-stdout": "1.3.1", + "commander": "2.15.1", + "debug": "3.1.0", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.5", + "he": "1.1.1", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "supports-color": "5.4.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/mocha/node_modules/glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "engines": { + "node": "*" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/promisify-child-process": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/promisify-child-process/-/promisify-child-process-2.1.2.tgz", + "integrity": "sha512-j2BRwNaM7fUwrd67avtqSTRevQXZiqS+T4Ky3VVaQdvzkPpsTByBAv+ZyBxuXgV/eUrCe2qYrOZvPvd+sMryeg==", + "dependencies": { + "@types/node": "^10.11.3" + } + }, + "node_modules/promisify-child-process/node_modules/@types/node": { + "version": "10.12.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.0.tgz", + "integrity": "sha512-3TUHC3jsBAB7qVRGxT6lWyYo2v96BMmD2PTcl47H25Lu7UXtFH/2qqmKiVrnel6Ne//0TFYf6uvNX+HW2FRkLQ==" + }, + "node_modules/psl": { + "version": "1.1.29", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", + "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==" + }, + "node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "node_modules/qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/semver": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sshpk": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.1.tgz", + "integrity": "sha512-mSdgNUaidk+dRU5MhYtN9zebdzF2iG0cNPWy8HG+W8y+fT1JnSkh0fzzpjOa0L7P8i1Rscz38t0h4gPcKz43xA==", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tar-stream": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.0.tgz", + "integrity": "sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw==", + "dependencies": { + "bl": "^3.0.0", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + }, + "node_modules/tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "dependencies": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "node_modules/typescript": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz", + "integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/vscode": { + "version": "1.1.37", + "resolved": "https://registry.npmjs.org/vscode/-/vscode-1.1.37.tgz", + "integrity": "sha512-vJNj6IlN7IJPdMavlQa1KoFB3Ihn06q1AiN3ZFI/HfzPNzbKZWPPuiU+XkpNOfGU5k15m4r80nxNPlM7wcc0wg==", + "deprecated": "This package is deprecated in favor of @types/vscode and vscode-test. For more information please read: https://code.visualstudio.com/updates/v1_36#_splitting-vscode-package-into-typesvscode-and-vscodetest", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "^7.1.2", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "mocha": "^5.2.0", + "semver": "^5.4.1", + "source-map-support": "^0.5.0", + "vscode-test": "^0.4.1" + }, + "bin": { + "vscode-install": "bin/install" + }, + "engines": { + "node": ">=8.9.3" + } + }, + "node_modules/vscode-jsonrpc": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz", + "integrity": "sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg==", + "engines": { + "node": ">=8.0.0 || >=10.0.0" + } + }, + "node_modules/vscode-languageclient": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-5.2.1.tgz", + "integrity": "sha512-7jrS/9WnV0ruqPamN1nE7qCxn0phkH5LjSgSp9h6qoJGoeAKzwKz/PF6M+iGA/aklx4GLZg1prddhEPQtuXI1Q==", + "dependencies": { + "semver": "^5.5.0", + "vscode-languageserver-protocol": "3.14.1" + }, + "engines": { + "vscode": "^1.30" + } + }, + "node_modules/vscode-languageserver": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-5.2.1.tgz", + "integrity": "sha512-GuayqdKZqAwwaCUjDvMTAVRPJOp/SLON3mJ07eGsx/Iq9HjRymhKWztX41rISqDKhHVVyFM+IywICyZDla6U3A==", + "dependencies": { + "vscode-languageserver-protocol": "3.14.1", + "vscode-uri": "^1.0.6" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.14.1.tgz", + "integrity": "sha512-IL66BLb2g20uIKog5Y2dQ0IiigW0XKrvmWiOvc0yXw80z3tMEzEnHjaGAb3ENuU7MnQqgnYJ1Cl2l9RvNgDi4g==", + "dependencies": { + "vscode-jsonrpc": "^4.0.0", + "vscode-languageserver-types": "3.14.0" + } + }, + "node_modules/vscode-languageserver-types": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz", + "integrity": "sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A==" + }, + "node_modules/vscode-test": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-0.4.3.tgz", + "integrity": "sha512-EkMGqBSefZH2MgW65nY05rdRSko15uvzq4VAPM5jVmwYuFQKE7eikKXNJDRxL+OITXHB6pI+a3XqqD32Y3KC5w==", + "dev": true, + "dependencies": { + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1" + }, + "engines": { + "node": ">=8.9.3" + } + }, + "node_modules/vscode-uri": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.6.tgz", + "integrity": "sha512-sLI2L0uGov3wKVb9EB+vIQBl9tVP90nqRvxSoJ35vI3NjxE8jfsE5DSOhWgSunHSZmKS4OCi2jrtfxK7uyp2ww==" + }, + "node_modules/vscode/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/vscode/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/vscode/node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/vscode/node_modules/https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/vscode/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dependencies": { + "async-limiter": "~1.0.0" + } + }, + "node_modules/zip-stream": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-2.1.2.tgz", + "integrity": "sha512-ykebHGa2+uzth/R4HZLkZh3XFJzivhVsjJt8bN3GvBzLaqqrUdRacu+c4QtnUgjkkQfsOuNE1JgLKMCPNmkKgg==", + "dependencies": { + "archiver-utils": "^2.1.0", + "compress-commons": "^2.1.1", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">= 6" + } + } + }, "dependencies": { + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true + }, "@types/archiver": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-2.1.3.tgz", @@ -810,12 +2146,6 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, - "querystringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", - "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==", - "dev": true - }, "readable-stream": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", @@ -853,12 +2183,6 @@ "uuid": "^3.3.2" } }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", - "dev": true - }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -963,16 +2287,6 @@ "integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==", "dev": true }, - "url-parse": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", - "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", - "dev": true, - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -994,18 +2308,65 @@ } }, "vscode": { - "version": "1.1.36", - "resolved": "https://registry.npmjs.org/vscode/-/vscode-1.1.36.tgz", - "integrity": "sha512-cGFh9jmGLcTapCpPCKvn8aG/j9zVQ+0x5hzYJq5h5YyUXVGa1iamOaB2M2PZXoumQPES4qeAP1FwkI0b6tL4bQ==", + "version": "1.1.37", + "resolved": "https://registry.npmjs.org/vscode/-/vscode-1.1.37.tgz", + "integrity": "sha512-vJNj6IlN7IJPdMavlQa1KoFB3Ihn06q1AiN3ZFI/HfzPNzbKZWPPuiU+XkpNOfGU5k15m4r80nxNPlM7wcc0wg==", "dev": true, "requires": { "glob": "^7.1.2", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", "mocha": "^5.2.0", - "request": "^2.88.0", "semver": "^5.4.1", "source-map-support": "^0.5.0", - "url-parse": "^1.4.4", "vscode-test": "^0.4.1" + }, + "dependencies": { + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } } }, "vscode-jsonrpc": { diff --git a/vscode-dotty/package.json b/vscode-dotty/package.json index 6cfe08d6f685..af7b08fed4f6 100644 --- a/vscode-dotty/package.json +++ b/vscode-dotty/package.json @@ -133,6 +133,6 @@ "@types/request": "^2.48.3", "@types/ws": "^6.0.3", "typescript": "^3.6.3", - "vscode": "^1.1.36" + "vscode": "^1.1.37" } } From 14b37e457d2446068b3c3e5d6384f9487cceec69 Mon Sep 17 00:00:00 2001 From: olsdavis Date: Sat, 12 Mar 2022 11:46:28 +0000 Subject: [PATCH 0002/1244] Reorder to avoid type erasure to Object issue + fix test --- .../dotty/tools/dotc/transform/LazyVals.scala | 18 +++++++++--------- .../tools/backend/jvm/DottyBytecodeTests.scala | 2 +- library/src/scala/runtime/LazyVals.scala | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala index 6126bc9b3e0b..f737098469f4 100644 --- a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala +++ b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala @@ -335,14 +335,14 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { * CAS(_x, lock, result) * lock.release() * else - * if current.isInstanceOf[A] then - * current.asInstanceOf[A] + * if current.isInstanceOf[Evaluating] then + * CAS(current, Evaluating, new Waiting) * else if current.isInstanceOf[NULL] then * null * else if current.isInstanceOf[Waiting] then * current.asInstanceOf[Waiting].awaitRelease() - * else // `current` is Evaluating - * CAS(current, Evaluating, new Waiting) + * else + * current.asInstanceOf[A] * end while * ``` * @@ -413,9 +413,9 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { val current = newSymbol(methodSymbol, lazyNme.current, Synthetic, defn.ObjectType) val ifNotNull = If( - ref(current).select(defn.Any_isInstanceOf).appliedToType(if needsBoxing(tp) then boxIfCan(tp) else tp), - Return(ref(current).ensureConforms(tp), methodSymbol), - // not an A + ref(current).select(defn.Any_isInstanceOf).appliedToTypeTree(evaluating), + ref(discardSymb).ensureApplied, + // not an Evaluating If( ref(current).select(defn.Any_isInstanceOf).appliedToTypeTree(nullValued), Return(defaultValue(tp), methodSymbol), @@ -423,8 +423,8 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { If( ref(current).select(defn.Any_isInstanceOf).appliedToTypeTree(waiting), ref(current).select(defn.Any_asInstanceOf).appliedToTypeTree(waiting).select(lazyNme.RLazyVals.waitingAwaitRelease).ensureApplied, - // not a Waiting, then is an Evaluating - ref(discardSymb).ensureApplied + // not a Waiting, then is an A + Return(ref(current).ensureConforms(tp), methodSymbol) ) ) ) diff --git a/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala b/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala index 9d6ff413f8a2..83b84496f1f5 100644 --- a/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala +++ b/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala @@ -595,7 +595,7 @@ class TestBCode extends DottyBytecodeTest { val clsIn = dir.lookupName("Test.class", directory = false).input val clsNode = loadClassNode(clsIn) val method = getMethod(clsNode, "test") - assertEquals(94, instructionsFromMethod(method).size) + assertEquals(122, instructionsFromMethod(method).size) } } diff --git a/library/src/scala/runtime/LazyVals.scala b/library/src/scala/runtime/LazyVals.scala index 0c1a6dd421e6..59c05029a11e 100644 --- a/library/src/scala/runtime/LazyVals.scala +++ b/library/src/scala/runtime/LazyVals.scala @@ -145,9 +145,9 @@ object LazyVals { def getOffset(clz: Class[_], name: String): Long = { if (debug) - clz.getDeclaredFields.foreach(println(_)) + clz.getDeclaredFields.nn.foreach(println(_)) val field = clz.getDeclaredField(name) - if java.lang.reflect.Modifier.isStatic(field.getModifiers()) then + if java.lang.reflect.Modifier.isStatic(field.nn.getModifiers()) then unsafe.staticFieldOffset(field) else unsafe.objectFieldOffset(field) From 91c03b1f7835d574290eba1ecf236e0f59fc2bf0 Mon Sep 17 00:00:00 2001 From: olsdavis Date: Mon, 4 Apr 2022 19:48:02 +0100 Subject: [PATCH 0003/1244] Keeping code for old release compatibility --- .../dotty/tools/dotc/transform/LazyVals.scala | 209 +++++++++++++++++- library/src/scala/runtime/LazyVals.scala | 9 +- project/MiMaFilters.scala | 19 +- tests/run/lazyVals_c3.0.0.check | 4 + tests/run/lazyVals_c3.0.0.scala | 13 ++ tests/run/lazyVals_c3.1.0.check | 4 + tests/run/lazyVals_c3.1.0.scala | 13 ++ 7 files changed, 255 insertions(+), 16 deletions(-) create mode 100644 tests/run/lazyVals_c3.0.0.check create mode 100644 tests/run/lazyVals_c3.0.0.scala create mode 100644 tests/run/lazyVals_c3.1.0.check create mode 100644 tests/run/lazyVals_c3.1.0.scala diff --git a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala index f737098469f4..061789fd3865 100644 --- a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala +++ b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala @@ -27,7 +27,13 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { * The map contains the list of the offset trees. */ class OffsetInfo(var defs: List[Tree]) + /** + * This map contains mutable state of transformation: OffsetDefs to be appended + * to companion object definitions, and number of bits currently used. + */ + class OldOffsetInfo(defs: List[Tree], var ord: Int) extends OffsetInfo(defs) private val appendOffsetDefs = mutable.Map.empty[Symbol, OffsetInfo] + private val oldAppendOffsetDefs = mutable.Map.empty[Symbol, OldOffsetInfo] override def phaseName: String = LazyVals.name @@ -53,6 +59,10 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { else nullables.toList } + private inline def isOldLazyVals(using ctx: Context): Boolean = + import dotty.tools.dotc.config.ScalaRelease._ + ctx.scalaRelease <= Release3_1 + private def initBlock(stats: List[Tree])(using Context): Block = stats match case Nil => throw new IllegalArgumentException("trying to create an empty Block") case x :: Nil => Block(List(x), EmptyTree) @@ -111,12 +121,13 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { } } - /** Append offset fields to companion objects - */ + /** + * Append offset fields to companion objects. + */ override def transformTemplate(template: Template)(using Context): Tree = { val cls = ctx.owner.asClass - - appendOffsetDefs.get(cls) match { + + (if isOldLazyVals then oldAppendOffsetDefs else appendOffsetDefs).get(cls) match { case None => template case Some(data) => data.defs.foreach(_.symbol.addAnnotation(Annotation(defn.ScalaStaticAnnot))) @@ -282,6 +293,16 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { } } + def transformMemberDefThreadSafe(x: ValOrDefDef)(using Context): Thicket = { + assert(!(x.symbol is Mutable)) + // generate old code for compatibility + // TODO find more meaningful names than old/new + if isOldLazyVals then + transformMemberDefThreadSafeOld(x) + else + transformMemberDefThreadSafeNew(x) + } + /** * Create a threadsafe lazy accessor equivalent to the following code: * ``` @@ -358,7 +379,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { * @param evaluating a reference to the `Evaluating` runtime object * @param nullValued a reference to the `NULL` runtime object */ - def mkThreadSafeDef(methodSymbol: TermSymbol, + def mkThreadSafeDefNew(methodSymbol: TermSymbol, claz: ClassSymbol, target: Symbol, rhs: Tree, @@ -434,8 +455,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { ret } - def transformMemberDefThreadSafe(x: ValOrDefDef)(using Context): Thicket = { - assert(!(x.symbol is Mutable)) + def transformMemberDefThreadSafeNew(x: ValOrDefDef)(using Context): Thicket = { import dotty.tools.dotc.core.Types._ import dotty.tools.dotc.core.Flags._ @@ -444,7 +464,6 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { val claz = x.symbol.owner.asClass val thizClass = Literal(Constant(claz.info)) val helperModule = requiredModule(runtimeModule) - val getOffset = Select(ref(helperModule), lazyNme.RLazyVals.getOffset) var offsetSymbol: TermSymbol = null def offsetName(id: Int) = s"${StdNames.nme.LAZY_FIELD_OFFSET}${if (x.symbol.owner.is(Module)) "_m_" else ""}$id".toTermName @@ -455,6 +474,11 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { val stat = x.symbol.isStatic if stat then containerSymbol.setFlag(JavaStatic) + val getOffset = + if stat then + Select(ref(helperModule), lazyNme.RLazyVals.getStaticOffset) + else + Select(ref(helperModule), lazyNme.RLazyVals.getOffset) val containerTree = ValDef(containerSymbol, nullLiteral) def staticOrFieldOff: Tree = getOffset.appliedTo(thizClass, Literal(Constant(containerName.toString))) @@ -485,10 +509,172 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { This(claz) val methodSymbol = x.symbol.asTerm - val accessor = mkThreadSafeDef(methodSymbol, claz, containerSymbol, x.rhs, tpe, offset, objCas, + val accessor = mkThreadSafeDefNew(methodSymbol, claz, containerSymbol, x.rhs, tpe, offset, objCas, ref(waiting), evaluating, nullValued, swapOver) Thicket(containerTree, accessor) } + + /** Create a threadsafe lazy accessor equivalent to such code + * ``` + * def methodSymbol(): Int = { + * while (true) { + * val flag = LazyVals.get(this, bitmap_offset) + * val state = LazyVals.STATE(flag, ) + * + * if (state == ) { + * return value_0 + * } else if (state == ) { + * if (LazyVals.CAS(this, bitmap_offset, flag, , )) { + * try { + * val result = + * value_0 = result + * nullable = null + * LazyVals.setFlag(this, bitmap_offset, , ) + * return result + * } + * catch { + * case ex => + * LazyVals.setFlag(this, bitmap_offset, , ) + * throw ex + * } + * } + * } else /* if (state == || state == ) */ { + * LazyVals.wait4Notification(this, bitmap_offset, flag, ) + * } + * } + * } + * ``` + */ + def mkThreadSafeDefOld(methodSymbol: TermSymbol, + claz: ClassSymbol, + ord: Int, + target: Symbol, + rhs: Tree, + tp: Type, + offset: Tree, + getFlag: Tree, + stateMask: Tree, + casFlag: Tree, + setFlagState: Tree, + waitOnLock: Tree)(using Context): DefDef = { + val initState = Literal(Constant(0)) + val computeState = Literal(Constant(1)) + val computedState = Literal(Constant(3)) + + val thiz = This(claz) + val fieldId = Literal(Constant(ord)) + + val flagSymbol = newSymbol(methodSymbol, lazyNme.flag, Synthetic, defn.LongType) + val flagDef = ValDef(flagSymbol, getFlag.appliedTo(thiz, offset)) + val flagRef = ref(flagSymbol) + + val stateSymbol = newSymbol(methodSymbol, lazyNme.state, Synthetic, defn.LongType) + val stateDef = ValDef(stateSymbol, stateMask.appliedTo(ref(flagSymbol), Literal(Constant(ord)))) + val stateRef = ref(stateSymbol) + + val compute = { + val resultSymbol = newSymbol(methodSymbol, lazyNme.result, Synthetic, tp) + val resultRef = ref(resultSymbol) + val stats = ( + ValDef(resultSymbol, rhs) :: + ref(target).becomes(resultRef) :: + (nullOut(nullableFor(methodSymbol)) :+ + setFlagState.appliedTo(thiz, offset, computedState, fieldId)) + ) + Block(stats, Return(resultRef, methodSymbol)) + } + + val retryCase = { + val caseSymbol = newSymbol(methodSymbol, nme.DEFAULT_EXCEPTION_NAME, Synthetic | Case, defn.ThrowableType) + val triggerRetry = setFlagState.appliedTo(thiz, offset, initState, fieldId) + CaseDef( + Bind(caseSymbol, ref(caseSymbol)), + EmptyTree, + Block(List(triggerRetry), Throw(ref(caseSymbol))) + ) + } + + val initialize = If( + casFlag.appliedTo(thiz, offset, flagRef, computeState, fieldId), + Try(compute, List(retryCase), EmptyTree), + unitLiteral + ) + + val condition = If( + stateRef.equal(computedState), + Return(ref(target), methodSymbol), + If( + stateRef.equal(initState), + initialize, + waitOnLock.appliedTo(thiz, offset, flagRef, fieldId) + ) + ) + + val loop = WhileDo(EmptyTree, Block(List(flagDef, stateDef), condition)) + DefDef(methodSymbol, loop) + } + + def transformMemberDefThreadSafeOld(x: ValOrDefDef)(using Context): Thicket = { + val tpe = x.tpe.widen.resultType.widen + val claz = x.symbol.owner.asClass + val thizClass = Literal(Constant(claz.info)) + val helperModule = requiredModule("scala.runtime.LazyVals") + val getOffset = Select(ref(helperModule), lazyNme.RLazyVals.getOffset) + var offsetSymbol: TermSymbol | Null = null + var flag: Tree = EmptyTree + var ord = 0 + + def offsetName(id: Int) = s"${StdNames.nme.LAZY_FIELD_OFFSET}${if (x.symbol.owner.is(Module)) "_m_" else ""}$id".toTermName + + // compute or create appropriate offsetSymbol, bitmap and bits used by current ValDef + oldAppendOffsetDefs.get(claz) match { + case Some(info) => + val flagsPerLong = (64 / scala.runtime.LazyVals.BITS_PER_LAZY_VAL).toInt + info.ord += 1 + ord = info.ord % flagsPerLong + val id = info.ord / flagsPerLong + val offsetById = offsetName(id) + if (ord != 0) // there are unused bits in already existing flag + offsetSymbol = claz.info.decl(offsetById) + .suchThat(sym => sym.is(Synthetic) && sym.isTerm) + .symbol.asTerm + else { // need to create a new flag + offsetSymbol = newSymbol(claz, offsetById, Synthetic, defn.LongType).enteredAfter(this) + offsetSymbol.nn.addAnnotation(Annotation(defn.ScalaStaticAnnot)) + val flagName = LazyBitMapName.fresh(id.toString.toTermName) + val flagSymbol = newSymbol(claz, flagName, containerFlags, defn.LongType).enteredAfter(this) + flag = ValDef(flagSymbol, Literal(Constant(0L))) + val offsetTree = ValDef(offsetSymbol.nn, getOffset.appliedTo(thizClass, Literal(Constant(flagName.toString)))) + info.defs = offsetTree :: info.defs + } + + case None => + offsetSymbol = newSymbol(claz, offsetName(0), Synthetic, defn.LongType).enteredAfter(this) + offsetSymbol.nn.addAnnotation(Annotation(defn.ScalaStaticAnnot)) + val flagName = LazyBitMapName.fresh("0".toTermName) + val flagSymbol = newSymbol(claz, flagName, containerFlags, defn.LongType).enteredAfter(this) + flag = ValDef(flagSymbol, Literal(Constant(0L))) + val offsetTree = ValDef(offsetSymbol.nn, getOffset.appliedTo(thizClass, Literal(Constant(flagName.toString)))) + oldAppendOffsetDefs += (claz -> new OldOffsetInfo(List(offsetTree), ord)) + } + + val containerName = LazyLocalName.fresh(x.name.asTermName) + val containerSymbol = newSymbol(claz, containerName, x.symbol.flags &~ containerFlagsMask | containerFlags, tpe, coord = x.symbol.coord).enteredAfter(this) + + val containerTree = ValDef(containerSymbol, defaultValue(tpe)) + + val offset = ref(offsetSymbol.nn) + val getFlag = Select(ref(helperModule), lazyNme.RLazyVals.get) + val setFlag = Select(ref(helperModule), lazyNme.RLazyVals.setFlag) + val wait = Select(ref(helperModule), lazyNme.RLazyVals.wait4Notification) + val state = Select(ref(helperModule), lazyNme.RLazyVals.state) + val cas = Select(ref(helperModule), lazyNme.RLazyVals.cas) + + val accessor = mkThreadSafeDefOld(x.symbol.asTerm, claz, ord, containerSymbol, x.rhs, tpe, offset, getFlag, state, cas, setFlag, wait) + if (flag eq EmptyTree) + Thicket(containerTree, accessor) + else Thicket(containerTree, flag, accessor) + } } object LazyVals { @@ -507,6 +693,11 @@ object LazyVals { val objCas: TermName = N.objCas.toTermName val getOffset: TermName = N.getOffset.toTermName val getStaticOffset: TermName = N.getStaticOffset.toTermName + val get: TermName = N.get.toTermName + val setFlag: TermName = N.setFlag.toTermName + val wait4Notification: TermName = N.wait4Notification.toTermName + val state: TermName = N.state.toTermName + val cas: TermName = N.cas.toTermName } val flag: TermName = "flag".toTermName val state: TermName = "state".toTermName diff --git a/library/src/scala/runtime/LazyVals.scala b/library/src/scala/runtime/LazyVals.scala index 59c05029a11e..1713fbe141ff 100644 --- a/library/src/scala/runtime/LazyVals.scala +++ b/library/src/scala/runtime/LazyVals.scala @@ -144,13 +144,10 @@ object LazyVals { } def getOffset(clz: Class[_], name: String): Long = { + val r = unsafe.objectFieldOffset(clz.getDeclaredField(name)) if (debug) - clz.getDeclaredFields.nn.foreach(println(_)) - val field = clz.getDeclaredField(name) - if java.lang.reflect.Modifier.isStatic(field.nn.getModifiers()) then - unsafe.staticFieldOffset(field) - else - unsafe.objectFieldOffset(field) + println(s"getOffset($clz, $name) = $r") + r } def getStaticOffset(clz: Class[_], name: String): Long = { diff --git a/project/MiMaFilters.scala b/project/MiMaFilters.scala index cac81eecc141..c6bf9cdd6471 100644 --- a/project/MiMaFilters.scala +++ b/project/MiMaFilters.scala @@ -19,6 +19,23 @@ object MiMaFilters { ProblemFilters.exclude[DirectMissingMethodProblem]("scala.quoted.Quotes#reflectModule#CompilationInfoModule.XmacroSettings"), // Private to the compiler - needed for forward binary compatibility - ProblemFilters.exclude[MissingClassProblem]("scala.annotation.since") + ProblemFilters.exclude[MissingClassProblem]("scala.annotation.since"), + + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.LazyVals.getStaticOffset"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.LazyVals.getStaticOffset"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.LazyVals.objCAS"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.LazyVals.objCAS"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.LazyVals#Names.evaluating"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.LazyVals#Names.getStaticOffset"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.LazyVals#Names.nullValued"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.LazyVals#Names.objCas"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.LazyVals#Names.waiting"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.LazyVals#Names.waitingAwaitRelease"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.LazyVals#Names.waitingRelease"), + ProblemFilters.exclude[MissingClassProblem]("scala.runtime.LazyVals$Evaluating$"), + ProblemFilters.exclude[MissingClassProblem]("scala.runtime.LazyVals$NULL$"), + ProblemFilters.exclude[MissingClassProblem]("scala.runtime.LazyVals$Waiting"), + ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.LazyVals.Evaluating"), + ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.LazyVals.NULL") ) } diff --git a/tests/run/lazyVals_c3.0.0.check b/tests/run/lazyVals_c3.0.0.check new file mode 100644 index 000000000000..a0aad90603ed --- /dev/null +++ b/tests/run/lazyVals_c3.0.0.check @@ -0,0 +1,4 @@ +computing x +x +computing y +y \ No newline at end of file diff --git a/tests/run/lazyVals_c3.0.0.scala b/tests/run/lazyVals_c3.0.0.scala new file mode 100644 index 000000000000..5df4069bc94c --- /dev/null +++ b/tests/run/lazyVals_c3.0.0.scala @@ -0,0 +1,13 @@ +// Compiled with 3.0.0 and run with current compiler +class Foo: + lazy val x = + println("computing x") + "x" + lazy val y = + println("computing y") + "y" + +@main def Test = + val foo = new Foo + println(foo.x) + println(foo.y) diff --git a/tests/run/lazyVals_c3.1.0.check b/tests/run/lazyVals_c3.1.0.check new file mode 100644 index 000000000000..a0aad90603ed --- /dev/null +++ b/tests/run/lazyVals_c3.1.0.check @@ -0,0 +1,4 @@ +computing x +x +computing y +y \ No newline at end of file diff --git a/tests/run/lazyVals_c3.1.0.scala b/tests/run/lazyVals_c3.1.0.scala new file mode 100644 index 000000000000..45e796ab46d3 --- /dev/null +++ b/tests/run/lazyVals_c3.1.0.scala @@ -0,0 +1,13 @@ +// Compiled with 3.1.0 and run with current compiler +class Foo: + lazy val x = + println("computing x") + "x" + lazy val y = + println("computing y") + "y" + +@main def Test = + val foo = new Foo + println(foo.x) + println(foo.y) \ No newline at end of file From b563979396e102f725553c7cdffd9f44c6426759 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 15 Jul 2021 12:54:30 +0200 Subject: [PATCH 0004/1244] Fix definition of enclosingExtensionMethod Now also finds enclosing methods outside the current class. Fixes #13075 --- .../tools/dotc/core/SymDenotations.scala | 3 +- tests/neg/i13075.scala | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 tests/neg/i13075.scala diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 112bd182b1ad..df2c195b9e74 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1140,11 +1140,10 @@ object SymDenotations { else NoSymbol /** The closest enclosing extension method containing this definition, - * provided the extension method appears in the same class. + * including methods outside the current class. */ final def enclosingExtensionMethod(using Context): Symbol = if this.is(ExtensionMethod) then symbol - else if this.isClass then NoSymbol else if this.exists then owner.enclosingExtensionMethod else NoSymbol diff --git a/tests/neg/i13075.scala b/tests/neg/i13075.scala new file mode 100644 index 000000000000..2a5ff70c0481 --- /dev/null +++ b/tests/neg/i13075.scala @@ -0,0 +1,40 @@ +object Implementing_Tuples: + + sealed trait Tup + case class ConsTup[T, H <: Tup](head: T, tail: H) extends Tup + case object EmptyTup extends Tup + + val *: = ConsTup // for unapply + type *:[H, T <: Tup] = ConsTup[H, T] // for type matching + type EmptyTup = EmptyTup.type // for type matching + + extension [H](head: H) + def *:[T <: Tup](tail: T) = ConsTup(head, tail) + + type Fold[T <: Tup, Seed, F[_,_]] = T match + case EmptyTup => Seed + case h *: t => Fold[t, F[Seed, h], F] + + extension [T <: Tup](v: T) + def fold[Seed, F[_,_]](seed: Seed)( + fn: [C, Acc] => (C, Acc) => F[C, Acc] + ): Fold[T, Seed, F] = + (v match + case EmptyTup => seed + case h *: t => t.fold(fn(h, seed))(fn) + ).asInstanceOf[Fold[T, Seed, F]] + + extension [T <: Tup](v: T) def reversed: Tup = + v.fold[EmptyTup, [C, Acc] =>> Acc match { + case h *: t => C *: h *: t + }](EmptyTup)( + [C, Acc] => (c: C, acc: Acc) => acc match + case _@(_ *: _) => c *: acc // error + ) + + @main def testProperFold = + val t = (1 *: '2' *: "foo" *: EmptyTup) + val reversed: (String *: Char *: Int *: EmptyTup) = t.reversed // error + println(reversed) + +end Implementing_Tuples \ No newline at end of file From 1e4766870e567e334efbb955dfdfaff97c35d03a Mon Sep 17 00:00:00 2001 From: Anatolii Kmetiuk Date: Wed, 24 Mar 2021 16:19:48 +0100 Subject: [PATCH 0005/1244] Fix #11318: add regression test --- tests/pos/i11318a.scala | 4 ++++ tests/pos/i11318b.scala | 13 +++++++++++++ tests/pos/i11318c.scala | 6 ++++++ 3 files changed, 23 insertions(+) create mode 100644 tests/pos/i11318a.scala create mode 100644 tests/pos/i11318b.scala create mode 100644 tests/pos/i11318c.scala diff --git a/tests/pos/i11318a.scala b/tests/pos/i11318a.scala new file mode 100644 index 000000000000..6422b32a375e --- /dev/null +++ b/tests/pos/i11318a.scala @@ -0,0 +1,4 @@ +extension(a: Int) + def b: Int = ??? + def h: Unit = + [A] => (r: Int) => b diff --git a/tests/pos/i11318b.scala b/tests/pos/i11318b.scala new file mode 100644 index 000000000000..b8bf2203d218 --- /dev/null +++ b/tests/pos/i11318b.scala @@ -0,0 +1,13 @@ +type FunctionK[A[_], B[_]] = [Z] => A[Z] => B[Z] +type ~>:[A[_], B[_]] = FunctionK[A, B] + +trait RepresentableK[F[_[_], _]]: + type RepresentationK[_] + + def tabulateK[A[_], C](f: RepresentationK ~>: A): F[A, C] + + extension[A[_], C](fa: F[A, C]) + def indexK: RepresentationK ~>: A + + def mapK[B[_]] (f: A ~>: B): F[B, C] = + tabulateK([Z] => (r: RepresentationK[Z]) => f(indexK(r))) diff --git a/tests/pos/i11318c.scala b/tests/pos/i11318c.scala new file mode 100644 index 000000000000..b1da38d7f6da --- /dev/null +++ b/tests/pos/i11318c.scala @@ -0,0 +1,6 @@ +extension(a: Int) + def b: Int = ??? + def h: Unit = + new Function1[Int, Int] { + def apply(r: Int): Int = b + } From 7b6b5d2bf077237b200db294936c57e724ca5f19 Mon Sep 17 00:00:00 2001 From: Boris Date: Fri, 16 Jul 2021 19:57:51 +0200 Subject: [PATCH 0006/1244] community build: Add monocle. (#11468) --- .gitmodules | 3 +++ community-build/community-projects/Monocle | 1 + .../src/scala/dotty/communitybuild/projects.scala | 7 +++++++ .../scala/dotty/communitybuild/CommunityBuildTest.scala | 1 + 4 files changed, 12 insertions(+) create mode 160000 community-build/community-projects/Monocle diff --git a/.gitmodules b/.gitmodules index 9a85a0254e85..e2584fc8396e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -180,6 +180,9 @@ [submodule "community-build/community-projects/protoquill"] path = community-build/community-projects/protoquill url = https://github.com/dotty-staging/protoquill.git +[submodule "community-build/community-projects/Monocle"] + path = community-build/community-projects/Monocle + url = https://github.com/dotty-staging/Monocle.git [submodule "community-build/community-projects/onnx-scala"] path = community-build/community-projects/onnx-scala url = https://github.com/dotty-staging/onnx-scala.git diff --git a/community-build/community-projects/Monocle b/community-build/community-projects/Monocle new file mode 160000 index 000000000000..4613afff874c --- /dev/null +++ b/community-build/community-projects/Monocle @@ -0,0 +1 @@ +Subproject commit 4613afff874c23d17bde580671ff29c7a13123d0 diff --git a/community-build/src/scala/dotty/communitybuild/projects.scala b/community-build/src/scala/dotty/communitybuild/projects.scala index 6128796bbff7..583dd0e94d37 100644 --- a/community-build/src/scala/dotty/communitybuild/projects.scala +++ b/community-build/src/scala/dotty/communitybuild/projects.scala @@ -660,6 +660,12 @@ object projects: dependencies = List(scalatest, scalatestplusJunit, scalatestplusScalacheck) ) + lazy val monocle = SbtCommunityProject( + project = "Monocle", + sbtTestCommand = "coreJVM/test; macrosJVM/test; testJVM/test", + dependencies = List(cats, munit, discipline, disciplineMunit) + ) + lazy val protoquill = SbtCommunityProject( project = "protoquill", sbtTestCommand = "test", @@ -777,6 +783,7 @@ def allProjects = List( projects.izumiReflect, projects.perspective, projects.akka, + projects.monocle, projects.protoquill, projects.onnxScala, projects.playJson, diff --git a/community-build/test/scala/dotty/communitybuild/CommunityBuildTest.scala b/community-build/test/scala/dotty/communitybuild/CommunityBuildTest.scala index e5a77ff33c4f..507920c7cc4b 100644 --- a/community-build/test/scala/dotty/communitybuild/CommunityBuildTest.scala +++ b/community-build/test/scala/dotty/communitybuild/CommunityBuildTest.scala @@ -127,6 +127,7 @@ class CommunityBuildTestB extends CommunityBuildTest: @Test def scalacheckEffect = projects.scalacheckEffect.run() @Test def scodec = projects.scodec.run() @Test def scodecBits = projects.scodecBits.run() + @Test def monocle = projects.monocle.run() @Test def simulacrumScalafixAnnotations = projects.simulacrumScalafixAnnotations.run() end CommunityBuildTestB From 7779fbb72f3a3843f38a17bce6d74a1f74b289b5 Mon Sep 17 00:00:00 2001 From: Andrzej Ratajczak Date: Tue, 20 Jul 2021 14:21:26 +0200 Subject: [PATCH 0007/1244] Fix MatchError in Scaladoc Scalajs script --- scaladoc-js/src/searchbar/code-snippets/CodeSnippets.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/scaladoc-js/src/searchbar/code-snippets/CodeSnippets.scala b/scaladoc-js/src/searchbar/code-snippets/CodeSnippets.scala index 50f0ad2d5df7..c8121b31860d 100644 --- a/scaladoc-js/src/searchbar/code-snippets/CodeSnippets.scala +++ b/scaladoc-js/src/searchbar/code-snippets/CodeSnippets.scala @@ -24,4 +24,5 @@ class CodeSnippets: }) a.classList.add("snippet-comment-button") e.insertBefore(a, e.firstChild) + case e => // skip } From ea9371fd1731703a81aea58c40c4908ff891dde7 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 16 Jul 2021 09:59:53 +0200 Subject: [PATCH 0008/1244] Add explanation to "already defined" message Fixes #13089 --- .../dotty/tools/dotc/reporting/messages.scala | 6 +++++- tests/neg/i13089.check | 12 +++++++++++ tests/neg/i13089.scala | 21 +++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tests/neg/i13089.check create mode 100644 tests/neg/i13089.scala diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index fb7c6d41e885..0e47c4a1ff57 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -1861,11 +1861,15 @@ import transform.SymUtils._ i" in ${conflicting.associatedFile}" else if conflicting.owner == owner then "" else i" in ${conflicting.owner}" + private def note = + if owner.is(Method) || conflicting.is(Method) then + "\n\nNote that overloaded methods must all be defined in the same group of toplevel definitions" + else "" def msg = if conflicting.isTerm != name.isTermName then em"$name clashes with $conflicting$where; the two must be defined together" else - em"$name is already defined as $conflicting$where" + em"$name is already defined as $conflicting$where$note" def explain = "" class PackageNameAlreadyDefined(pkg: Symbol)(using Context) extends NamingMsg(PackageNameAlreadyDefinedID) { diff --git a/tests/neg/i13089.check b/tests/neg/i13089.check new file mode 100644 index 000000000000..ed0f9d5effd9 --- /dev/null +++ b/tests/neg/i13089.check @@ -0,0 +1,12 @@ +-- [E161] Naming Error: tests/neg/i13089.scala:6:8 --------------------------------------------------------------------- +6 | def fails : Unit = {} // error + | ^^^^^^^^^^^^^^^^^^^^^ + | fails is already defined as method fails in tests/neg/i13089.scala + | + | Note that overloaded methods must all be defined in the same group of toplevel definitions +-- [E161] Naming Error: tests/neg/i13089.scala:8:6 --------------------------------------------------------------------- +8 | def baz(x: String): Boolean = true // error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | baz is already defined as method baz in tests/neg/i13089.scala + | + | Note that overloaded methods must all be defined in the same group of toplevel definitions diff --git a/tests/neg/i13089.scala b/tests/neg/i13089.scala new file mode 100644 index 000000000000..5b91996de837 --- /dev/null +++ b/tests/neg/i13089.scala @@ -0,0 +1,21 @@ +package pkg: + + trait Bar + + extension (bar : Bar) + def fails : Unit = {} // error + + def baz(x: String): Boolean = true // error + +package pkg: + + trait Foo + extension (foo : Foo) + def fails : Unit = {} + def works : Unit = {} + + extension (bar : Bar) + def works : Unit = {} + + def baz(x: Int): Boolean = true + From b8fc378301d3980dbf0bd1abb078ad0c8ad7f8b0 Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Tue, 20 Jul 2021 18:45:34 +0200 Subject: [PATCH 0009/1244] Escape illegal characters in scaladoc code blocks Fixes #13107 --- scaladoc/src/dotty/tools/scaladoc/renderers/DocRenderer.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/DocRenderer.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/DocRenderer.scala index 6f52abb0a61b..76d88a8a0bb3 100644 --- a/scaladoc/src/dotty/tools/scaladoc/renderers/DocRenderer.scala +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/DocRenderer.scala @@ -46,7 +46,7 @@ class DocRender(signatureRenderer: SignatureRenderer)(using DocContext): case 5 => h5(content) case 6 => h6(content) case Paragraph(text) => p(renderElement(text)) - case Code(data: String) => pre(code(raw(data))) // TODO add classes + case Code(data: String) => pre(code(raw(data.escapeReservedTokens))) // TODO add classes case HorizontalRule => hr case UnorderedList(items) => ul(listItems(items)) From b1f5157f77acbf28ecd83245a83e52bf6740fd50 Mon Sep 17 00:00:00 2001 From: Julien Richard-Foy Date: Sat, 17 Jul 2021 17:04:37 +0200 Subject: [PATCH 0010/1244] Mark website content as outdated. The Scala 3 documentation is now hosted at https://docs.scala-lang.org. --- docs/_layouts/main.html | 5 +++++ docs/css/dottydoc.css | 4 ++-- .../reference/changed-features/compiler-plugins.md | 1 + .../reference/changed-features/eta-expansion-spec.md | 1 + .../docs/reference/changed-features/eta-expansion.md | 1 + .../changed-features/implicit-conversions-spec.md | 1 + .../changed-features/implicit-conversions.md | 1 + .../changed-features/implicit-resolution.md | 1 + docs/docs/reference/changed-features/imports.md | 1 + .../changed-features/interpolation-escapes.md | 1 + .../reference/changed-features/lazy-vals-init.md | 1 + .../reference/changed-features/main-functions.md | 1 + docs/docs/reference/changed-features/match-syntax.md | 1 + .../reference/changed-features/numeric-literals.md | 1 + docs/docs/reference/changed-features/operators.md | 1 + .../changed-features/overload-resolution.md | 1 + .../reference/changed-features/pattern-bindings.md | 1 + .../reference/changed-features/pattern-matching.md | 1 + .../changed-features/structural-types-spec.md | 1 + .../reference/changed-features/structural-types.md | 1 + .../docs/reference/changed-features/type-checking.md | 1 + .../reference/changed-features/type-inference.md | 1 + .../reference/changed-features/vararg-splices.md | 1 + docs/docs/reference/changed-features/wildcards.md | 1 + .../contextual/by-name-context-parameters.md | 1 + docs/docs/reference/contextual/context-bounds.md | 1 + .../reference/contextual/context-functions-spec.md | 1 + docs/docs/reference/contextual/context-functions.md | 1 + docs/docs/reference/contextual/conversions.md | 1 + docs/docs/reference/contextual/derivation-macro.md | 1 + docs/docs/reference/contextual/derivation.md | 1 + docs/docs/reference/contextual/extension-methods.md | 1 + docs/docs/reference/contextual/given-imports.md | 1 + docs/docs/reference/contextual/givens.md | 1 + docs/docs/reference/contextual/motivation.md | 1 + .../reference/contextual/multiversal-equality.md | 1 + .../reference/contextual/relationship-implicits.md | 1 + .../right-associative-extension-methods.md | 1 + docs/docs/reference/contextual/type-classes.md | 1 + docs/docs/reference/contextual/using-clauses.md | 1 + docs/docs/reference/dropped-features/auto-apply.md | 1 + .../dropped-features/class-shadowing-spec.md | 1 + .../reference/dropped-features/class-shadowing.md | 1 + docs/docs/reference/dropped-features/delayed-init.md | 3 ++- docs/docs/reference/dropped-features/do-while.md | 1 + .../reference/dropped-features/early-initializers.md | 1 + .../reference/dropped-features/existential-types.md | 1 + docs/docs/reference/dropped-features/limit22.md | 1 + docs/docs/reference/dropped-features/macros.md | 1 + .../reference/dropped-features/nonlocal-returns.md | 1 + .../reference/dropped-features/package-objects.md | 1 + .../reference/dropped-features/procedure-syntax.md | 1 + docs/docs/reference/dropped-features/symlits.md | 1 + .../reference/dropped-features/this-qualifier.md | 1 + .../reference/dropped-features/type-projection.md | 1 + .../dropped-features/weak-conformance-spec.md | 1 + .../reference/dropped-features/weak-conformance.md | 1 + .../docs/reference/dropped-features/wildcard-init.md | 1 + docs/docs/reference/dropped-features/xml.md | 1 + docs/docs/reference/enums/adts.md | 1 + docs/docs/reference/enums/desugarEnums.md | 1 + docs/docs/reference/enums/enums.md | 1 + .../reference/metaprogramming/compiletime-ops.md | 1 + docs/docs/reference/metaprogramming/inline.md | 1 + docs/docs/reference/metaprogramming/macros-spec.md | 1 + docs/docs/reference/metaprogramming/macros.md | 1 + docs/docs/reference/metaprogramming/reflection.md | 1 + docs/docs/reference/metaprogramming/staging.md | 1 + docs/docs/reference/metaprogramming/tasty-inspect.md | 1 + docs/docs/reference/metaprogramming/toc.md | 1 + .../new-types/dependent-function-types-spec.md | 1 + .../reference/new-types/dependent-function-types.md | 1 + .../reference/new-types/intersection-types-spec.md | 1 + docs/docs/reference/new-types/intersection-types.md | 1 + docs/docs/reference/new-types/match-types.md | 1 + .../new-types/polymorphic-function-types.md | 1 + docs/docs/reference/new-types/type-lambdas-spec.md | 1 + docs/docs/reference/new-types/type-lambdas.md | 1 + docs/docs/reference/new-types/union-types-spec.md | 1 + docs/docs/reference/new-types/union-types.md | 1 + .../reference/other-new-features/control-syntax.md | 1 + .../other-new-features/creator-applications.md | 1 + .../reference/other-new-features/explicit-nulls.md | 1 + docs/docs/reference/other-new-features/export.md | 1 + .../docs/reference/other-new-features/indentation.md | 1 + .../other-new-features/kind-polymorphism.md | 1 + docs/docs/reference/other-new-features/matchable.md | 1 + .../reference/other-new-features/opaques-details.md | 1 + docs/docs/reference/other-new-features/opaques.md | 1 + .../reference/other-new-features/open-classes.md | 1 + .../other-new-features/parameter-untupling-spec.md | 1 + .../other-new-features/parameter-untupling.md | 1 + .../other-new-features/safe-initialization.md | 1 + docs/docs/reference/other-new-features/targetName.md | 1 + .../other-new-features/threadUnsafe-annotation.md | 1 + .../reference/other-new-features/trait-parameters.md | 1 + .../other-new-features/transparent-traits.md | 1 + docs/docs/reference/other-new-features/type-test.md | 1 + docs/docs/reference/overview.md | 1 + docs/docs/reference/syntax.md | 1 + docs/docs/resources/talks.md | 1 + docs/docs/usage/getting-started.md | 1 + docs/docs/usage/ide-support.md | 1 + docs/docs/usage/language-versions.md | 1 + docs/docs/usage/worksheet-mode.md | 1 + scaladoc/resources/dotty_res/styles/colors.css | 12 ++++++++---- 106 files changed, 119 insertions(+), 7 deletions(-) diff --git a/docs/_layouts/main.html b/docs/_layouts/main.html index c7aff4f96c5a..e265ac1bed16 100644 --- a/docs/_layouts/main.html +++ b/docs/_layouts/main.html @@ -2,6 +2,11 @@ layout: base ---
+ {% if page.movedTo %} + + {% endif %} {{ content }}
+ + + diff --git a/project/Build.scala b/project/Build.scala index 8520a5de6839..bc9121bdcac3 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -24,6 +24,7 @@ import sbtbuildinfo.BuildInfoPlugin.autoImport._ import scala.util.Properties.isJavaAtLeast import org.portablescala.sbtplatformdeps.PlatformDepsPlugin.autoImport._ +import org.scalajs.linker.interface.ModuleInitializer object DottyJSPlugin extends AutoPlugin { import Build._ @@ -1246,6 +1247,7 @@ object Build { // Note: the two tasks below should be one, but a bug in Tasty prevents that val generateScalaDocumentation = inputKey[Unit]("Generate documentation for dotty lib") val generateTestcasesDocumentation = taskKey[Unit]("Generate documentation for testcases, usefull for debugging tests") + val renderScaladocScalajsToFile = inputKey[Unit]("Copy the output of the scaladoc js files") lazy val `scaladoc-testcases` = project.in(file("scaladoc-testcases")). dependsOn(`scala3-compiler-bootstrapped`). @@ -1254,8 +1256,12 @@ object Build { enablePlugins(DottyJSPlugin). dependsOn(`scala3-library-bootstrappedJS`). settings( + Compile / scalaJSMainModuleInitializer := (sys.env.get("scaladoc.projectFormat") match { + case Some("md") => Some(ModuleInitializer.mainMethod("dotty.tools.scaladoc.Main", "markdownMain")) + case _ => Some(ModuleInitializer.mainMethod("dotty.tools.scaladoc.Main", "main")) + }), Test / fork := false, - scalaJSUseMainModuleInitializer := true, + Compile / scalaJSUseMainModuleInitializer := true, libraryDependencies += ("org.scala-js" %%% "scalajs-dom" % "1.1.0").cross(CrossVersion.for3Use2_13) ) @@ -1309,7 +1315,7 @@ object Build { ). settings( Compile / resourceGenerators += Def.task { - val jsDestinationFile = (Compile / resourceManaged).value / "dotty_res" / "scripts" / "searchbar.js" + val jsDestinationFile = (Compile / resourceManaged).value / "dotty_res" / "scripts" / "scaladoc-scalajs.js" sbt.IO.copyFile((`scaladoc-js` / Compile / fullOptJS).value.data, jsDestinationFile) Seq(jsDestinationFile) }.taskValue, @@ -1439,6 +1445,23 @@ object Build { ) }.value, + renderScaladocScalajsToFile := Def.inputTask { + val extraArgs = spaceDelimited("").parsed + val (destJS, destCSS, csses) = extraArgs match { + case js :: css :: tail => (js, css, tail) + case js :: Nil => (js, "", Nil) + case _ => throw new IllegalArgumentException("No js destination provided") + } + val jsDestinationFile: File = Paths.get(destJS).toFile + sbt.IO.copyFile((`scaladoc-js` / Compile / fullOptJS).value.data, jsDestinationFile) + csses.map { file => + val cssDesitnationFile = Paths.get(destCSS).toFile / file + val cssSourceFile = (`scaladoc-js` / Compile / resourceDirectory).value / file + sbt.IO.copyFile(cssSourceFile, cssDesitnationFile) + cssDesitnationFile + } + }.evaluated, + Test / buildInfoKeys := Seq[BuildInfoKey]( (Test / Build.testcasesOutputDir), (Test / Build.testcasesSourceRoot), diff --git a/project/scripts/genDocsScalaLang b/project/scripts/genDocsScalaLang new file mode 100755 index 000000000000..8125c5cc0e8b --- /dev/null +++ b/project/scripts/genDocsScalaLang @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +set -e +shopt -s extglob # needed for rm everything but x +echo "Working directory: $PWD" + +GENDOC_EXTRA_ARGS=$@ +GIT_HEAD=$(git rev-parse HEAD) # save current head for commit message in gh-pages +PREVIOUS_SNAPSHOTS_DIR="$PWD/../prev_snapshots" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >& /dev/null && pwd)" +SITE_OUT_DIR="$PWD/docs/_site" + +DOCS_SCALA_LANG_DIR="$PWD/docsScalaLang" + +rm -rf $DOCS_SCALA_LANG_DIR +mkdir -pv $DOCS_SCALA_LANG_DIR +git clone "https://github.com/scala/docs.scala-lang.git" $DOCS_SCALA_LANG_DIR + +SBT="$SCRIPT_DIR/sbt" +mkdir -pv $SITE_OUT_DIR +env "scaladoc.projectFormat=md" "$SBT" "scaladoc/renderScaladocScalajsToFile $DOCS_SCALA_LANG_DIR/scripts/scaladoc-scalajs.js $DOCS_SCALA_LANG_DIR/resources/css code-snippets.css" +"dist/target/pack/bin/scaladoc" "-d" "$SITE_OUT_DIR" "-format" "md" "-siteroot" "docs" "/dev/null" + +if [ ! -d "$SITE_OUT_DIR" ]; then + echo "Output directory did not exist: $SITE_OUT_DIR" 1>&2 + exit 1 +fi + +# Copy reference and scaladoc docs +cp -rf "$SITE_OUT_DIR/docs/reference"/* "$DOCS_SCALA_LANG_DIR/_scala3-reference" +cp -rf "$SITE_OUT_DIR/docs/usage/scaladoc"/* "$DOCS_SCALA_LANG_DIR/_overviews/scala3-scaladoc" + +cp -rf "$SITE_OUT_DIR/docs/reference/contextual/motivation.md" "$DOCS_SCALA_LANG_DIR/_scala3-reference/contextual.md" +cp -rf "$SITE_OUT_DIR/docs/reference/metaprogramming/toc.md" "$DOCS_SCALA_LANG_DIR/_scala3-reference/metaprogramming.md" +cp -rf "$SITE_OUT_DIR/docs/resources/talks.md" "$DOCS_SCALA_LANG_DIR/scala3/talks.md" +cp -rf "$SITE_OUT_DIR/docs/usage/getting-started.md" "$DOCS_SCALA_LANG_DIR/scala3/getting-started.md" +cp -rf "$SITE_OUT_DIR/docs/usage/language-versions.md" "$DOCS_SCALA_LANG_DIR/_scala3-reference/language-versions.md" +cp -rf "$SITE_OUT_DIR/docs/usage/worksheet-mode.md" "$DOCS_SCALA_LANG_DIR/_overviews/scala3-book/tools-worksheets.md" + + +# Copy csses and html importing these assets +cp -f "$SITE_OUT_DIR/styles/colors.css" "$DOCS_SCALA_LANG_DIR/resources/css/colors.css" +cp -f "$PWD/docs/docsScalaLangResources/scaladoc-assets.html" "$DOCS_SCALA_LANG_DIR/_includes/scaladoc-assets.html" + +# Hack inclusion of these assests by the docs.scala-lang jekyll builder +echo "{% include scaladoc-assets.html %}" >> "$DOCS_SCALA_LANG_DIR/_layouts/inner-page-parent-dropdown.html" diff --git a/scaladoc-js/src/Main.scala b/scaladoc-js/src/Main.scala index a7d7e8d552be..f7075766e3b4 100644 --- a/scaladoc-js/src/Main.scala +++ b/scaladoc-js/src/Main.scala @@ -1,9 +1,22 @@ package dotty.tools.scaladoc -object Main extends App { - Searchbar() - SocialLinks() - CodeSnippets() - DropdownHandler() - Ux() -} +object Main: + + private def common(): Unit = + CodeSnippets() + + def main(): Unit = + Searchbar() + SocialLinks() + DropdownHandler() + Ux() + common() + + /** + * This main is conditionally enabled by system env variable `scaladoc.projectFormat=md` + * passed in ./projects/scripts/genDocsScalaLang + * The reason why we have to pass the condition by env variable is because js is build before scaladoc, + * so we cannot access its args + */ + def markdownMain(): Unit = + common() diff --git a/scaladoc/src/dotty/tools/scaladoc/Scaladoc.scala b/scaladoc/src/dotty/tools/scaladoc/Scaladoc.scala index 487eebf7a1b6..bd8493ebb9ec 100644 --- a/scaladoc/src/dotty/tools/scaladoc/Scaladoc.scala +++ b/scaladoc/src/dotty/tools/scaladoc/Scaladoc.scala @@ -59,7 +59,8 @@ object Scaladoc: versionsDictionaryUrl: Option[String] = None, generateInkuire : Boolean = false, apiSubdirectory : Boolean = false, - scastieConfiguration: String = "" + scastieConfiguration: String = "", + projectFormat: String = "html", ) def run(args: Array[String], rootContext: CompilerContext): Reporter = @@ -236,7 +237,8 @@ object Scaladoc: versionsDictionaryUrl.nonDefault, generateInkuire.get, apiSubdirectory.get, - scastieConfiguration.get + scastieConfiguration.get, + projectFormat.get, ) (Some(docArgs), newContext) } @@ -245,6 +247,10 @@ object Scaladoc: given docContext: DocContext = new DocContext(args, ctx) val module = ScalaModuleProvider.mkModule() - new dotty.tools.scaladoc.renderers.HtmlRenderer(module.rootPackage, module.members).render() + val renderer = args.projectFormat match + case "html" => new dotty.tools.scaladoc.renderers.HtmlRenderer(module.rootPackage, module.members) + case "md" => new dotty.tools.scaladoc.renderers.MarkdownRenderer(module.rootPackage, module.members) + + renderer.render() report.inform("generation completed successfully") docContext diff --git a/scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala b/scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala index e9058c504147..ba077d31a8fd 100644 --- a/scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala +++ b/scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala @@ -128,6 +128,16 @@ class ScaladocSettings extends SettingGroup with AllScalaSettings: val scastieConfiguration: Setting[String] = StringSetting("-scastie-configuration", "Scastie configuration", "Additional configuration passed to Scastie in code snippets", "") + + val projectFormat: Setting[String] = + ChoiceSetting( + "-format", + "format of the static site output", + "Format of the static site output. The default value is html, which converts all static articles into a webpage. " + + "The md format only preprocess markdown files and should not be used as a direct output, but rather as a sources generator for an outer templating engine like Jekyll", + List("html", "md"), + "html" + ) def scaladocSpecificSettings: Set[Setting[_]] = Set(sourceLinks, legacySourceLink, syntax, revision, externalDocumentationMappings, socialLinks, skipById, skipByRegex, deprecatedSkipPackages, docRootContent, snippetCompiler, generateInkuire, scastieConfiguration) diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala index 8db1dc2e5b87..3b6876238436 100644 --- a/scaladoc/src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala @@ -14,120 +14,21 @@ import java.nio.file.Files import java.nio.file.FileVisitOption import java.io.File -case class Page(link: Link, content: Member | ResolvedTemplate | String, children: Seq[Page]): - def withNewChildren(newChildren: Seq[Page]) = copy(children = children ++ newChildren) +class HtmlRenderer(rootPackage: Member, members: Map[DRI, Member])(using ctx: DocContext) + extends Renderer(rootPackage, members, extension = "html"): - def withTitle(newTitle: String) = copy(link = link.copy(name = newTitle)) - - def hasFrame = content match - case t: ResolvedTemplate => t.hasFrame - case _ => true - -class HtmlRenderer(rootPackage: Member, val members: Map[DRI, Member])(using ctx: DocContext) - extends SiteRenderer, Resources, Locations, Writer: - private val args = summon[DocContext].args - val staticSite = summon[DocContext].staticSiteContext - - val effectiveMembers = members - - private def memberPage(member: Member): Page = - val childrenPages = member.members.filter(_.needsOwnPage) - Page(Link(member.name, member.dri), member, childrenPages.map(memberPage)) - - val navigablePage: Page = - val rootPckPage = memberPage(rootPackage) - staticSite match - case None => rootPckPage.withTitle(args.name) - case Some(siteContext) => - val (indexes, templates) = siteContext.templates.partition(f => - f.templateFile.isIndexPage() && f.file.toPath.getParent() == siteContext.docsPath) - if (indexes.size > 1) - val msg = s"ERROR: Multiple index pages for doc found ${indexes.map(_.file)}" - report.error(msg) - - val templatePages = templates.map(templateToPage(_, siteContext)) - - indexes.headOption match - case None if templatePages.isEmpty=> - rootPckPage.withTitle(args.name) - case None => - Page(Link(args.name, docsRootDRI),"", templatePages :+ rootPckPage.withTitle("API")) - case Some(indexPage) => - val newChildren = templatePages :+ rootPckPage.withTitle("API") - templateToPage(indexPage, siteContext).withNewChildren(newChildren) - - val hiddenPages: Seq[Page] = - staticSite match - case None => - Seq(navigablePage.copy( // Add index page that is a copy of api/index.html - link = navigablePage.link.copy(dri = docsRootDRI), - children = Nil - )) - case Some(siteContext) => - // In case that we do not have an index page and we do not have any API entries - // we want to create empty index page, so there is one - val actualIndexTemplate = siteContext.indexTemplate() match { - case None if effectiveMembers.isEmpty => Seq(siteContext.emptyIndexTemplate) - case templates => templates.toSeq - } - - (siteContext.orphanedTemplates ++ actualIndexTemplate).map(templateToPage(_, siteContext)) - - /** - * Here we have to retrive index pages from hidden pages and replace fake index pages in navigable page tree. - */ - val allPages: Seq[Page] = - def traversePages(page: Page): (Page, Seq[Page]) = - val (newChildren, newPagesToRemove): (Seq[Page], Seq[Page]) = page.children.map(traversePages(_)).foldLeft((Seq[Page](), Seq[Page]())) { - case ((pAcc, ptrAcc), (p, ptr)) => (pAcc :+ p, ptrAcc ++ ptr) - } - hiddenPages.find(_.link == page.link) match - case None => - (page.copy(children = newChildren), newPagesToRemove) - case Some(newPage) => - (newPage.copy(children = newChildren), newPagesToRemove :+ newPage) - - val (newNavigablePage, pagesToRemove) = traversePages(navigablePage) - - val all = newNavigablePage +: hiddenPages.filterNot(pagesToRemove.contains) - // We need to check for conflicts only if we have top-level member called blog or docs - val hasPotentialConflict = - rootPackage.members.exists(m => m.name.startsWith("docs") || m.name.startsWith("blog")) - - if hasPotentialConflict then - def walk(page: Page): Unit = - if page.link.dri.isStaticFile then - val dest = absolutePath(page.link.dri) - if apiPaths.contains(dest) then - report.error(s"Conflict between static page and API member for $dest. $pathsConflictResoultionMsg") - page.children.foreach(walk) - - all.foreach (walk) - - all - - def renderContent(page: Page) = page.content match - case m: Member => - val signatureRenderer = new SignatureRenderer: - def currentDri: DRI = page.link.dri - def link(dri: DRI): Option[String] = - Some(pathToPage(currentDri, dri)).filter(_ != UnresolvedLocationLink) - - MemberRenderer(signatureRenderer).fullMember(m) - case t: ResolvedTemplate => siteContent(page.link.dri, t) - case a: String => raw(a) - - - def renderPage(page: Page, parents: Vector[Link]): Seq[String] = - val newParents = parents :+ page.link - val content = html( + override def pageContent(page: Page, parents: Vector[Link]): AppliedTag = + html( mkHead(page), body( if !page.hasFrame then renderContent(page) - else mkFrame(page.link, newParents, renderContent(page)) + else mkFrame(page.link, parents, renderContent(page)) ) ) - write(page.link.dri, content) +: page.children.flatMap(renderPage(_, newParents)) + + override def render(): Unit = + val renderedResources = renderResources() + super.render() private def specificResources(page: Page): Set[String] = page.children.toSet.flatMap(specificResources) ++ (page.content match @@ -157,10 +58,6 @@ class HtmlRenderer(rootPackage: Member, val members: Map[DRI, Member])(using ctx val resources = siteResourcesPaths.toSeq.map(pathToResource) ++ allResources(allPages) ++ onlyRenderedResources resources.flatMap(renderResource) - def render(): Unit = - val renderedResources = renderResources() - val sites = allPages.map(renderPage(_, Vector.empty)) - def mkHead(page: Page): AppliedTag = val resources = page.content match case t: ResolvedTemplate => @@ -229,14 +126,6 @@ class HtmlRenderer(rootPackage: Member, val members: Map[DRI, Member])(using ctx renderNested(navigablePage, toplevel = true)._2 - private def canonicalUrl(l: String): AppliedTag | String = - val canon = args.docCanonicalBaseUrl - if !canon.isEmpty then - val canonicalUrl = if canon.endsWith("/") then canon else canon + "/" - link(rel := "canonical", href := canonicalUrl + l) - else - "" // return empty tag - private def hasSocialLinks = !args.socialLinks.isEmpty private def socialLinks(whiteIcon: Boolean = true) = diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala index 23b5c9d9479a..81baf34b778e 100644 --- a/scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala @@ -21,7 +21,7 @@ trait Locations(using ctx: DocContext): // We generate this collection only if there may be a conflict with resources. // Potentially can be quite big. - lazy val apiPaths = effectiveMembers.keySet.filterNot(_.isStaticFile).map(absolutePath) + lazy val apiPaths = effectiveMembers.keySet.filterNot(_.isStaticFile).map(absolutePath(_)) var cache = new JHashMap[DRI, Seq[String]]() @@ -80,7 +80,7 @@ trait Locations(using ctx: DocContext): pathToRaw(from, to.split("/").toList) def resolveRoot(dri: DRI, path: String): String = resolveRoot(rawLocation(dri), path) - def absolutePath(dri: DRI): String = rawLocation(dri).mkString("", "/", ".html") + def absolutePath(dri: DRI, extension: String = "html"): String = rawLocation(dri).mkString("", "/", s".$extension") def resolveLink(dri: DRI, url: String): String = if URI(url).isAbsolute then url else resolveRoot(dri, url) diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/MarkdownRenderer.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/MarkdownRenderer.scala new file mode 100644 index 000000000000..b49c1e268678 --- /dev/null +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/MarkdownRenderer.scala @@ -0,0 +1,28 @@ +package dotty.tools.scaladoc +package renderers + +import util.HTML._ +import collection.JavaConverters._ +import java.net.URI +import java.net.URL +import dotty.tools.scaladoc.site._ +import scala.util.Try +import org.jsoup.Jsoup +import java.nio.file.Paths +import java.nio.file.Path +import java.nio.file.Files +import java.nio.file.FileVisitOption +import java.io.File + +class MarkdownRenderer(rootPackage: Member, members: Map[DRI, Member])(using ctx: DocContext) + extends Renderer(rootPackage, members, extension = "md"): + + override def render(): Unit = + renderResources() + super.render() + + override def pageContent(page: Page, parents: Vector[Link]): AppliedTag = + renderContent(page) + + private def renderResources(): Seq[String] = + allResources(Nil).flatMap(renderResource) diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/Renderer.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/Renderer.scala new file mode 100644 index 000000000000..7664a542c2bb --- /dev/null +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/Renderer.scala @@ -0,0 +1,149 @@ +package dotty.tools.scaladoc +package renderers + +import util.HTML._ +import collection.JavaConverters._ +import java.net.URI +import java.net.URL +import dotty.tools.scaladoc.site._ +import scala.util.Try +import org.jsoup.Jsoup +import java.nio.file.Paths +import java.nio.file.Path +import java.nio.file.Files +import java.nio.file.FileVisitOption +import java.io.File + +case class Page(link: Link, content: Member | ResolvedTemplate | String, children: Seq[Page]): + def withNewChildren(newChildren: Seq[Page]) = copy(children = children ++ newChildren) + + def withTitle(newTitle: String) = copy(link = link.copy(name = newTitle)) + + def hasFrame = content match + case t: ResolvedTemplate => t.hasFrame + case _ => true + +abstract class Renderer(rootPackage: Member, val members: Map[DRI, Member], protected val extension: String = "html")(using ctx: DocContext) + extends SiteRenderer, Resources, Locations, Writer: + protected val args = summon[DocContext].args + val staticSite = summon[DocContext].staticSiteContext + + val effectiveMembers = members + + protected def memberPage(member: Member): Page = + val childrenPages = member.members.filter(_.needsOwnPage) + Page(Link(member.name, member.dri), member, childrenPages.map(memberPage)) + + val navigablePage: Page = + val rootPckPage = memberPage(rootPackage) + staticSite match + case None => rootPckPage.withTitle(args.name) + case Some(siteContext) => + val (indexes, templates) = siteContext.templates.partition(f => + f.templateFile.isIndexPage() && f.file.toPath.getParent() == siteContext.docsPath) + if (indexes.size > 1) + val msg = s"ERROR: Multiple index pages for doc found ${indexes.map(_.file)}" + report.error(msg) + + val templatePages = templates.map(templateToPage(_, siteContext)) + + indexes.headOption match + case None if templatePages.isEmpty=> + rootPckPage.withTitle(args.name) + case None => + Page(Link(args.name, docsRootDRI),"", templatePages :+ rootPckPage.withTitle("API")) + case Some(indexPage) => + val newChildren = templatePages :+ rootPckPage.withTitle("API") + templateToPage(indexPage, siteContext).withNewChildren(newChildren) + + val hiddenPages: Seq[Page] = + staticSite match + case None => + Seq(navigablePage.copy( // Add index page that is a copy of api/index.html + link = navigablePage.link.copy(dri = docsRootDRI), + children = Nil + )) + case Some(siteContext) => + // In case that we do not have an index page and we do not have any API entries + // we want to create empty index page, so there is one + val actualIndexTemplate = siteContext.indexTemplate() match { + case None if effectiveMembers.isEmpty => Seq(siteContext.emptyIndexTemplate) + case templates => templates.toSeq + } + + (siteContext.orphanedTemplates ++ actualIndexTemplate).map(templateToPage(_, siteContext)) + + /** + * Here we have to retrive index pages from hidden pages and replace fake index pages in navigable page tree. + */ + val allPages: Seq[Page] = + def traversePages(page: Page): (Page, Seq[Page]) = + val (newChildren, newPagesToRemove): (Seq[Page], Seq[Page]) = page.children.map(traversePages(_)).foldLeft((Seq[Page](), Seq[Page]())) { + case ((pAcc, ptrAcc), (p, ptr)) => (pAcc :+ p, ptrAcc ++ ptr) + } + hiddenPages.find(_.link == page.link) match + case None => + (page.copy(children = newChildren), newPagesToRemove) + case Some(newPage) => + (newPage.copy(children = newChildren), newPagesToRemove :+ newPage) + + val (newNavigablePage, pagesToRemove) = traversePages(navigablePage) + + val all = newNavigablePage +: hiddenPages.filterNot(pagesToRemove.contains) + // We need to check for conflicts only if we have top-level member called blog or docs + val hasPotentialConflict = + rootPackage.members.exists(m => m.name.startsWith("docs") || m.name.startsWith("blog")) + + if hasPotentialConflict then + def walk(page: Page): Unit = + if page.link.dri.isStaticFile then + val dest = absolutePath(page.link.dri) + if apiPaths.contains(dest) then + report.error(s"Conflict between static page and API member for $dest. $pathsConflictResoultionMsg") + page.children.foreach(walk) + + all.foreach(walk) + + all + + def renderContent(page: Page) = page.content match + case m: Member => + val signatureRenderer = new SignatureRenderer: + def currentDri: DRI = page.link.dri + def link(dri: DRI): Option[String] = + Some(pathToPage(currentDri, dri)).filter(_ != UnresolvedLocationLink) + + MemberRenderer(signatureRenderer).fullMember(m) + case t: ResolvedTemplate => siteContent(page.link.dri, t) + case a: String => raw(a) + + + + protected def canonicalUrl(l: String): AppliedTag | String = + val canon = args.docCanonicalBaseUrl + if !canon.isEmpty then + val canonicalUrl = if canon.endsWith("/") then canon else canon + "/" + link(rel := "canonical", href := canonicalUrl + l) + else + "" // return empty tag + + /** + * Main method rendering all the pages + */ + def render(): Unit = + val sites = allPages.map(renderPage(_, Vector.empty)) + + /** + * Handler to prepare the content to be rendered. It's a good place to organize frame, footers, front-matter, etc. + */ + def pageContent(page: Page, parents: Vector[Link]): AppliedTag + + /** + * Method to be overriden by concrete renderer to render single page + */ + def renderPage(page: Page, parents: Vector[Link]): Seq[String] = + val newParents = parents :+ page.link + val content = pageContent(page, newParents) + write(page.link.dri, content, extension) +: page.children.flatMap(renderPage(_, newParents)) + + diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala index 7dc40f68c322..3cb97316ad2f 100644 --- a/scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala @@ -105,7 +105,7 @@ trait Resources(using ctx: DocContext) extends Locations, Writer: "scripts/components/Input.js", "scripts/components/FilterGroup.js", "scripts/components/Filter.js", - "scripts/searchbar.js" + "scripts/scaladoc-scalajs.js" ).map(dottyRes) val urls = List( diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/SiteRenderer.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/SiteRenderer.scala index a1dd1e4e71fb..a5a30b41681b 100644 --- a/scaladoc/src/dotty/tools/scaladoc/renderers/SiteRenderer.scala +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/SiteRenderer.scala @@ -56,11 +56,24 @@ trait SiteRenderer(using DocContext) extends Locations: else processLocalLink(str) - val document = Jsoup.parse(content.resolved.code) - document.select("a").forEach(element => - element.attr("href", processLocalLinkWithGuard(element.attr("href"))) - ) - document.select("img").forEach { element => - element.attr("src", processLocalLink(element.attr("src"))) - } // foreach does not work here. Why? - raw(document.outerHtml()) + summon[DocContext].args.projectFormat match + case "html" => + val document = Jsoup.parse(content.resolved.code) + document.select("a").forEach(element => + element.attr("href", processLocalLinkWithGuard(element.attr("href"))) + ) + document.select("img").forEach { element => + element.attr("src", processLocalLink(element.attr("src"))) + } // foreach does not work here. Why? + raw(document.outerHtml()) + case "md" => + val links = """(? s"[${m.group(1)}](${processLocalLink(m.group(2))})" + ), + m => s"[${m.group(1)}](${processLocalLinkWithGuard(m.group(2))})" + )) diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/Writer.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/Writer.scala index 313cef340d41..029da21bdda7 100644 --- a/scaladoc/src/dotty/tools/scaladoc/renderers/Writer.scala +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/Writer.scala @@ -18,8 +18,8 @@ trait Writer(using ctx: DocContext) extends Locations: if !Files.exists(absPath.getParent) then Files.createDirectories(absPath.getParent) absPath - def write(dri: DRI, content: AppliedTag): String = - val path = absolutePath(dri) + def write(dri: DRI, content: AppliedTag, extension: String = "html"): String = + val path = absolutePath(dri, extension) Files.write(dest(path), content.toString.getBytes) path diff --git a/scaladoc/src/dotty/tools/scaladoc/site/FrontMatterRenderer.scala b/scaladoc/src/dotty/tools/scaladoc/site/FrontMatterRenderer.scala new file mode 100644 index 000000000000..7590927cb248 --- /dev/null +++ b/scaladoc/src/dotty/tools/scaladoc/site/FrontMatterRenderer.scala @@ -0,0 +1,20 @@ +package dotty.tools.scaladoc +package site + + +/** + * Object for rendering yaml front-matter for preprocessed markdowns. + */ +object FrontMatterRenderer: + def render(properties: Map[String, Object]): String = + + def renderProperties(newProps: Map[String, Object]): List[String] = newProps.collect { + case (k: String, v: String) => s"$p: $v" + } + + val rows = renderProperties(properties) ++ renderProperties(properties("page")) + + rows.mkString("---\n", "\n", "\n---") + "\n\n\n\n" + + diff --git a/scaladoc/src/dotty/tools/scaladoc/site/StaticSiteContext.scala b/scaladoc/src/dotty/tools/scaladoc/site/StaticSiteContext.scala index 8d09a949c143..ded1a1ff20db 100644 --- a/scaladoc/src/dotty/tools/scaladoc/site/StaticSiteContext.scala +++ b/scaladoc/src/dotty/tools/scaladoc/site/StaticSiteContext.scala @@ -40,7 +40,7 @@ class StaticSiteContext( lazy val layouts: Map[String, TemplateFile] = val layoutRoot = new File(root, "_layouts") val dirs: Array[File] = Option(layoutRoot.listFiles()).getOrElse(Array()) - dirs.map { it => loadTemplateFile(it) }.map { it => it.name -> it }.toMap + dirs.map { it => loadTemplateFile(it)(using this) }.map { it => it.name -> it }.toMap lazy val sideBarConfig = val sidebarFile = root.toPath.resolve("sidebar.yml") @@ -96,7 +96,7 @@ class StaticSiteContext( val msg = s"ERROR: Multiple index pages for $from found in ${indexes.map(_.file)}" throw new java.lang.RuntimeException(msg) - val templateFile = if (from.isDirectory) loadIndexPage() else loadTemplateFile(from) + val templateFile = if (from.isDirectory) loadIndexPage() else loadTemplateFile(from)(using this) def dateFrom(p: LoadedTemplate, default: String = "1900-01-01"): String = val pageSettings = p.templateFile.settings.get("page").collect{ case m: Map[String @unchecked, _] => m } diff --git a/scaladoc/src/dotty/tools/scaladoc/site/common.scala b/scaladoc/src/dotty/tools/scaladoc/site/common.scala index bb09cd92f452..5873863ed6c0 100644 --- a/scaladoc/src/dotty/tools/scaladoc/site/common.scala +++ b/scaladoc/src/dotty/tools/scaladoc/site/common.scala @@ -14,13 +14,14 @@ import com.vladsch.flexmark.ext.yaml.front.matter.{AbstractYamlFrontMatterVisito import com.vladsch.flexmark.parser.{Parser, ParserEmulationProfile} import com.vladsch.flexmark.util.options.{DataHolder, MutableDataSet} import com.vladsch.flexmark.ext.wikilink.WikiLinkExtension +import com.vladsch.flexmark.formatter.Formatter import scala.collection.JavaConverters._ val docsRootDRI: DRI = DRI(location = "docs/index", symbolUUID = staticFileSymbolUUID) val apiPageDRI: DRI = DRI(location = "api/index") -val defaultMarkdownOptions: DataHolder = +def defaultMarkdownOptions(using ctx: StaticSiteContext): DataHolder = new MutableDataSet() .setFrom(ParserEmulationProfile.COMMONMARK.getOptions) .set(AnchorLinkExtension.ANCHORLINKS_WRAP_TEXT, false) @@ -36,7 +37,10 @@ val defaultMarkdownOptions: DataHolder = YamlFrontMatterExtension.create(), StrikethroughExtension.create(), WikiLinkExtension.create(), - tasty.comments.markdown.SnippetRenderingExtension + (ctx.args.projectFormat match + case "html" => tasty.comments.markdown.SnippetRenderingExtension + case "md" => tasty.comments.markdown.SnippetFormattingExtension + ), )) def emptyTemplate(file: File, title: String): TemplateFile = TemplateFile( @@ -55,9 +59,9 @@ def emptyTemplate(file: File, title: String): TemplateFile = TemplateFile( final val ConfigSeparator = "---" final val LineSeparator = "\n" -val yamlParser: Parser = Parser.builder(defaultMarkdownOptions).build() +def yamlParser(using ctx: StaticSiteContext): Parser = Parser.builder(defaultMarkdownOptions).build() -def loadTemplateFile(file: File): TemplateFile = { +def loadTemplateFile(file: File)(using ctx: StaticSiteContext): TemplateFile = { val lines = Files.readAllLines(file.toPath).asScala.toList val (config, content) = if (lines.head == ConfigSeparator) { @@ -77,7 +81,7 @@ def loadTemplateFile(file: File): TemplateFile = { val globalKeys = Set("extraJS", "extraCSS", "layout", "hasFrame", "name", "title") val allSettings = yamlCollector.getData.asScala.toMap.transform(getSettingValue) val (global, inner) = allSettings.partition((k,_) => globalKeys.contains(k)) - val settings = Map("page" -> inner) + val settings = Map("page" -> inner) ++ global def stringSetting(settings: Map[String, Object], name: String): Option[String] = settings.get(name).map { case List(elem: String) => elem diff --git a/scaladoc/src/dotty/tools/scaladoc/site/templates.scala b/scaladoc/src/dotty/tools/scaladoc/site/templates.scala index 6d59a87e5f85..7b4f4939f72e 100644 --- a/scaladoc/src/dotty/tools/scaladoc/site/templates.scala +++ b/scaladoc/src/dotty/tools/scaladoc/site/templates.scala @@ -14,6 +14,7 @@ import com.vladsch.flexmark.ext.yaml.front.matter.{AbstractYamlFrontMatterVisito import com.vladsch.flexmark.parser.{Parser, ParserEmulationProfile} import com.vladsch.flexmark.util.options.{DataHolder, MutableDataSet} import com.vladsch.flexmark.html.HtmlRenderer +import com.vladsch.flexmark.formatter.Formatter import liqp.Template import scala.collection.JavaConverters._ @@ -88,7 +89,7 @@ case class TemplateFile( if (ctx.resolving.contains(file.getAbsolutePath)) throw new RuntimeException(s"Cycle in templates involving $file: ${ctx.resolving}") - val layoutTemplate = layout.map(name => + val layoutTemplate = layout.filter(_ => ssctx.args.projectFormat == "html").map(name => ctx.layouts.getOrElse(name, throw new RuntimeException(s"No layouts named $name in ${ctx.layouts}"))) def asJavaElement(o: Object): Object = o match @@ -107,9 +108,15 @@ case class TemplateFile( val parser: Parser = Parser.builder(defaultMarkdownOptions).build() val parsedMd = parser.parse(rendered) val processed = FlexmarkSnippetProcessor.processSnippets(parsedMd, None, snippetCheckingFunc, withContext = false)(using ssctx.outerCtx) - HtmlRenderer.builder(defaultMarkdownOptions).build().render(processed) - layoutTemplate match - case None => ResolvedPage(code, resources ++ ctx.resources) - case Some(layoutTemplate) => - layoutTemplate.resolveInner(ctx.nest(code, file, resources)) + ssctx.args.projectFormat match + case "html" => HtmlRenderer.builder(defaultMarkdownOptions).build().render(processed) + case "md" => + FrontMatterRenderer.render(settings) + + Formatter.builder(defaultMarkdownOptions).build().render(processed) + + + if layoutTemplate.isEmpty || ssctx.args.projectFormat == "md" then + ResolvedPage(code, resources ++ ctx.resources) + else + layoutTemplate.get.resolveInner(ctx.nest(code, file, resources)) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SnippetFormattingExtension.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SnippetFormattingExtension.scala new file mode 100644 index 000000000000..7833c0c5d669 --- /dev/null +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SnippetFormattingExtension.scala @@ -0,0 +1,40 @@ +package dotty.tools.scaladoc +package tasty.comments.markdown + +import dotty.tools.scaladoc.snippets._ + +import com.vladsch.flexmark.formatter._ +import com.vladsch.flexmark.parser._ +import com.vladsch.flexmark.ext.wikilink._ +import com.vladsch.flexmark.ext.wikilink.internal.WikiLinkLinkRefProcessor +import com.vladsch.flexmark.util.ast._ +import com.vladsch.flexmark.util.options._ +import com.vladsch.flexmark.util.sequence.BasedSequence +import com.vladsch.flexmark._ + +/** + * SnippetFormattingExtension is a clone of the [[SnippetRenderingExtension]] used as a fallback strategy when the `-format` setting is set up to `md` + */ +object SnippetFormattingExtension extends Formatter.FormatterExtension: + + def rendererOptions(opt: MutableDataHolder): Unit = () + + object ExtendedFencedCodeBlockHandler extends CustomNodeFormatter[ExtendedFencedCodeBlock]: + override def render(node: ExtendedFencedCodeBlock, c: NodeFormatterContext, markdown: MarkdownWriter): Unit = + markdown.append( + SnippetRenderer.renderSnippetWithMessages(node) + ) + + object Format extends NodeFormatter: + override def getNodeFormattingHandlers: JSet[NodeFormattingHandler[?]] = + JSet( + new NodeFormattingHandler(classOf[ExtendedFencedCodeBlock], ExtendedFencedCodeBlockHandler), + ) + + def getNodeClasses: JSet[Class[?]] = null + + object Factory extends NodeFormatterFactory: + override def create(options: DataHolder): NodeFormatter = Format + + def extend(formatterBuilder: Formatter.Builder) = + formatterBuilder.nodeFormatterFactory(Factory) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SnippetRenderer.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SnippetRenderer.scala index 7a27bddab892..55f3ac31a7bb 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SnippetRenderer.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SnippetRenderer.scala @@ -137,4 +137,12 @@ object SnippetRenderer: def renderSnippetWithMessages(snippetName: Option[String], codeLines: Seq[String], messages: Seq[SnippetCompilerMessage], hasContext: Boolean): String = val transformedLines = wrapCodeLines.andThen(addCompileMessages(messages)).apply(codeLines).map(_.toHTML) val codeHTML = s"""${transformedLines.mkString("")}""" - s"""
$codeHTML
${snippetName.fold("")(snippetLabel(_))}
""" \ No newline at end of file + s"""
$codeHTML
${snippetName.fold("")(snippetLabel(_))}
""" + + def renderSnippetWithMessages(node: ExtendedFencedCodeBlock): String = + renderSnippetWithMessages( + node.name, + node.codeBlock.getContentChars.toString.split("\n").map(_ + "\n").toSeq, + node.compilationResult.toSeq.flatMap(_.messages), + node.hasContext + ) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SnippetRenderingExtension.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SnippetRenderingExtension.scala index ae2de8afdef9..7a7edc0f5e86 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SnippetRenderingExtension.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SnippetRenderingExtension.scala @@ -13,17 +13,17 @@ import com.vladsch.flexmark.util.options._ import com.vladsch.flexmark.util.sequence.BasedSequence import com.vladsch.flexmark._ +/** + * SnippetRenderingExtension is responsible for running an analysis for scala codeblocks in the static documentation/scaladoc comments. + * For each codeblock we run compiler to check whether snippet works in the newest scala version and to produce rich html codeblocks with + * compiler warnings/errors for IDE-like live experience. + */ object SnippetRenderingExtension extends HtmlRenderer.HtmlRendererExtension: def rendererOptions(opt: MutableDataHolder): Unit = () object ExtendedFencedCodeBlockHandler extends CustomNodeRenderer[ExtendedFencedCodeBlock]: override def render(node: ExtendedFencedCodeBlock, c: NodeRendererContext, html: HtmlWriter): Unit = html.raw( - SnippetRenderer.renderSnippetWithMessages( - node.name, - node.codeBlock.getContentChars.toString.split("\n").map(_ + "\n").toSeq, - node.compilationResult.toSeq.flatMap(_.messages), - node.hasContext - ) + SnippetRenderer.renderSnippetWithMessages(node) ) object Render extends NodeRenderer: @@ -36,4 +36,4 @@ object SnippetRenderingExtension extends HtmlRenderer.HtmlRendererExtension: override def create(options: DataHolder): NodeRenderer = Render def extend(htmlRendererBuilder: HtmlRenderer.Builder, tpe: String): Unit = - htmlRendererBuilder.nodeRendererFactory(Factory) \ No newline at end of file + htmlRendererBuilder.nodeRendererFactory(Factory) From 66946ff5ac61de0646028f8b007782f0f82ea137 Mon Sep 17 00:00:00 2001 From: Andrzej Ratajczak Date: Tue, 28 Sep 2021 11:10:52 +0200 Subject: [PATCH 0728/1244] Fix API after rebase conflicts --- project/Build.scala | 2 +- project/scripts/genDocsScalaLang | 14 +++++++++----- .../tools/scaladoc/site/FrontMatterRenderer.scala | 6 +++--- .../src/dotty/tools/scaladoc/site/templates.scala | 15 ++++++++++++++- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/project/Build.scala b/project/Build.scala index bc9121bdcac3..65daf5ee280c 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -1365,7 +1365,7 @@ object Build { Seq(inkuireDestinationFile) }.taskValue, libraryDependencies ++= Dependencies.flexmarkDeps ++ Seq( - "nl.big-o" % "liqp" % "0.6.7", + "nl.big-o" % "liqp" % "0.6.8", "org.jsoup" % "jsoup" % "1.13.1", // Needed to process .html files for static site Dependencies.`jackson-dataformat-yaml`, diff --git a/project/scripts/genDocsScalaLang b/project/scripts/genDocsScalaLang index 8125c5cc0e8b..a59cc4509fd9 100755 --- a/project/scripts/genDocsScalaLang +++ b/project/scripts/genDocsScalaLang @@ -19,7 +19,7 @@ git clone "https://github.com/scala/docs.scala-lang.git" $DOCS_SCALA_LANG_DIR SBT="$SCRIPT_DIR/sbt" mkdir -pv $SITE_OUT_DIR env "scaladoc.projectFormat=md" "$SBT" "scaladoc/renderScaladocScalajsToFile $DOCS_SCALA_LANG_DIR/scripts/scaladoc-scalajs.js $DOCS_SCALA_LANG_DIR/resources/css code-snippets.css" -"dist/target/pack/bin/scaladoc" "-d" "$SITE_OUT_DIR" "-format" "md" "-siteroot" "docs" "/dev/null" +"bin/scaladoc" "-d" "$SITE_OUT_DIR" "-format" "md" "-siteroot" "docs" "/dev/null" if [ ! -d "$SITE_OUT_DIR" ]; then echo "Output directory did not exist: $SITE_OUT_DIR" 1>&2 @@ -30,12 +30,9 @@ fi cp -rf "$SITE_OUT_DIR/docs/reference"/* "$DOCS_SCALA_LANG_DIR/_scala3-reference" cp -rf "$SITE_OUT_DIR/docs/usage/scaladoc"/* "$DOCS_SCALA_LANG_DIR/_overviews/scala3-scaladoc" -cp -rf "$SITE_OUT_DIR/docs/reference/contextual/motivation.md" "$DOCS_SCALA_LANG_DIR/_scala3-reference/contextual.md" -cp -rf "$SITE_OUT_DIR/docs/reference/metaprogramming/toc.md" "$DOCS_SCALA_LANG_DIR/_scala3-reference/metaprogramming.md" cp -rf "$SITE_OUT_DIR/docs/resources/talks.md" "$DOCS_SCALA_LANG_DIR/scala3/talks.md" cp -rf "$SITE_OUT_DIR/docs/usage/getting-started.md" "$DOCS_SCALA_LANG_DIR/scala3/getting-started.md" -cp -rf "$SITE_OUT_DIR/docs/usage/language-versions.md" "$DOCS_SCALA_LANG_DIR/_scala3-reference/language-versions.md" -cp -rf "$SITE_OUT_DIR/docs/usage/worksheet-mode.md" "$DOCS_SCALA_LANG_DIR/_overviews/scala3-book/tools-worksheets.md" +cp -rf "$SITE_OUT_DIR/docs/usage/tools-worksheets.md" "$DOCS_SCALA_LANG_DIR/_overviews/scala3-book/tools-worksheets.md" # Copy csses and html importing these assets @@ -44,3 +41,10 @@ cp -f "$PWD/docs/docsScalaLangResources/scaladoc-assets.html" "$DOCS_SCALA_LANG_ # Hack inclusion of these assests by the docs.scala-lang jekyll builder echo "{% include scaladoc-assets.html %}" >> "$DOCS_SCALA_LANG_DIR/_layouts/inner-page-parent-dropdown.html" + +# Push changes to fork branch +cd $DOCS_SCALA_LANG_DIR +git remote add barkingbad git@github.com:BarkingBad/docs.scala-lang.git +git add . +git commit -m "Update docs from dotty repo" +git push -f barkingbad main:pregenerated-page diff --git a/scaladoc/src/dotty/tools/scaladoc/site/FrontMatterRenderer.scala b/scaladoc/src/dotty/tools/scaladoc/site/FrontMatterRenderer.scala index 7590927cb248..dde7650a9480 100644 --- a/scaladoc/src/dotty/tools/scaladoc/site/FrontMatterRenderer.scala +++ b/scaladoc/src/dotty/tools/scaladoc/site/FrontMatterRenderer.scala @@ -9,10 +9,10 @@ object FrontMatterRenderer: def render(properties: Map[String, Object]): String = def renderProperties(newProps: Map[String, Object]): List[String] = newProps.collect { - case (k: String, v: String) => s"$p: $v" - } + case (k: String, v: String) => s"$k: $v" + }.toList - val rows = renderProperties(properties) ++ renderProperties(properties("page")) + val rows = renderProperties(properties) ++ renderProperties(properties("page").asInstanceOf[Map[String, Object]]) rows.mkString("---\n", "\n", "\n---") + "\n\n\n\n" diff --git a/scaladoc/src/dotty/tools/scaladoc/site/templates.scala b/scaladoc/src/dotty/tools/scaladoc/site/templates.scala index 7b4f4939f72e..22755290840e 100644 --- a/scaladoc/src/dotty/tools/scaladoc/site/templates.scala +++ b/scaladoc/src/dotty/tools/scaladoc/site/templates.scala @@ -16,6 +16,9 @@ import com.vladsch.flexmark.util.options.{DataHolder, MutableDataSet} import com.vladsch.flexmark.html.HtmlRenderer import com.vladsch.flexmark.formatter.Formatter import liqp.Template +import liqp.TemplateContext +import liqp.tags.Tag +import liqp.nodes.LNode import scala.collection.JavaConverters._ import scala.io.Source @@ -101,7 +104,17 @@ case class TemplateFile( // Library requires mutable maps.. val mutableProperties = new JHashMap(ctx.properties.transform((_, v) => asJavaElement(v)).asJava) - val rendered = Template.parse(this.rawCode).render(mutableProperties) + + // Register escaping {% link ... %} in markdown + val tag = new Tag("link"): + override def render(context: TemplateContext, nodes: Array[? <: LNode]): Object = + val link = super.asString(nodes(0).render(context)) + s"{% link $link %}" + + val rendered = ssctx.args.projectFormat match + case "html" => Template.parse(this.rawCode).`with`(tag).render(mutableProperties) + case "md" => this.rawCode + // We want to render markdown only if next template is html val code = if (isHtml || layoutTemplate.exists(!_.isHtml)) rendered else // Snippet compiler currently supports markdown only From 1d928bcaa1c855f6bb1480769b00c07f358e017c Mon Sep 17 00:00:00 2001 From: Andrzej Ratajczak Date: Mon, 4 Oct 2021 13:36:02 +0200 Subject: [PATCH 0729/1244] Fix some broken likns for static site and configure CI for nightly pushes to docs.scala-lang --- .github/workflows/ci.yaml | 25 +++++++++++++++---- docs/docs/usage/getting-started.md | 8 +++--- docs/docs/usage/scaladoc/search-engine.md | 2 +- project/CopyDocs.scala | 30 ++++++++++++++++++----- project/scripts/genDocsScalaLang | 7 ------ 5 files changed, 49 insertions(+), 23 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index fa8c67c5990c..24d04be110f5 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -470,9 +470,12 @@ jobs: if: "(github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && github.repository == 'lampepfl/dotty'" env: NIGHTLYBUILD: yes - BOT_TOKEN: ${{ secrets.BOT_TOKEN }} # If you need to change this: - # Generate one at https://github.com/settings/tokens - # Make sure you have the write permissions to the repo: https://github.com/lampepfl/dotty-website + DOTTY_WEBSITE_BOT_TOKEN: ${{ secrets.BOT_TOKEN }} # If you need to change this: + # Generate one at https://github.com/settings/tokens + # Make sure you have the write permissions to the repo: https://github.com/lampepfl/dotty-website + DOCS_SCALALANG_BOT_TOKEN: ${{ secrets.DOCS_SCALALANG_BOT_TOKEN }} # If you need to change this: + # Generate one at https://github.com/settings/tokens + # Make sure you have the write permissions to the repo: https://github.com/scala/docs.scala-lang steps: - name: Reset existing repo @@ -494,14 +497,26 @@ jobs: run: | ./project/scripts/genDocs -doc-snapshot - - name: Deploy Website + - name: Deploy Website to dotty-website uses: peaceiris/actions-gh-pages@v3 with: - personal_token: ${{ secrets.BOT_TOKEN }} + personal_token: ${{ DOTTY_WEBSITE_BOT_TOKEN }} publish_dir: docs/_site external_repository: lampepfl/dotty-website publish_branch: gh-pages + - name: Generate docs.scala-lang preprocessed files + run: | + ./project/scripts/genDocsScalaLang + + - name: Deploy Website to docs.scala-lang + uses: peaceiris/actions-gh-pages@v3 + with: + personal_token: ${{ DOCS_SCALALANG_BOT_TOKEN }} + publish_dir: docsScalaLang + external_repository: scala/docs.scala-lang + publish_branch: dev + publish_release: runs-on: [self-hosted, Linux] container: diff --git a/docs/docs/usage/getting-started.md b/docs/docs/usage/getting-started.md index c888285fb39c..1c43d6e5adbb 100644 --- a/docs/docs/usage/getting-started.md +++ b/docs/docs/usage/getting-started.md @@ -50,7 +50,7 @@ For more information, read the [coursier-cli documentation](https://get-coursier You only need two tools to compile, run, test, and package a Scala project: Java 8 or 11, and sbt. To install these manually: -1. Download Java from [Oracle Java 8](https://www.oracle.com/java/technologies/javase-jdk8-downloads.html), [Oracle Java 11](https://www.oracle.com/java/technologies/javase-jdk11-downloads.html), or [AdoptOpenJDK 8/11](https://adoptopenjdk.net/). Refer to [JDK Compatibility](/overviews/jdk-compatibility/overview.html) for Scala/Java compatibility detail. +1. Download Java from [Oracle Java 8](https://www.oracle.com/java/technologies/javase-jdk8-downloads.html), [Oracle Java 11](https://www.oracle.com/java/technologies/javase-jdk11-downloads.html), or [AdoptOpenJDK 8/11](https://adoptopenjdk.net/). Refer to [JDK Compatibility](https://docs.scala-lang.org/overviews/jdk-compatibility/overview.html) for Scala/Java compatibility detail. 2. Install [sbt](https://www.scala-sbt.org/download.html) @@ -87,7 +87,7 @@ hello-world/ ``` The scala file `Main.scala` in `src/main/scala` is all we need for now. -More documentation about sbt can be found in the [Scala Book](/scala3/book/scala-tools.html) and in the official sbt [documentation](https://www.scala-sbt.org/1.x/docs/index.html) +More documentation about sbt can be found in the [Scala Book](https://docs.scala-lang.org/scala3/book/scala-tools.html) and in the official sbt [documentation](https://www.scala-sbt.org/1.x/docs/index.html) {% comment %} @@ -156,8 +156,8 @@ Then type `exit` or press `[Ctrl][d]` to exit sbt and return to your command lin Now that you’ve created a first “Hello, world” example with Scala 3, you’re ready for some next steps. Consider checking out: -- [The Scala 3 Book](/scala3/book/introduction.html), which provides a set of short lessons introducing Scala’s main features -- [The migration guide](/scala3/guides/migration/compatibility-intro.html) helps you to migrate your existing Scala 2 code base to Scala 3. +- [The Scala 3 Book](https://docs.scala-lang.org/scala3/book/introduction.html), which provides a set of short lessons introducing Scala’s main features +- [The migration guide](https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html) helps you to migrate your existing Scala 2 code base to Scala 3. When you want to connect with other Scala users, there are several mailing lists and real-time chat rooms available. Check out our [Scala community page](https://scala-lang.org/community/) for a list of these resources, and for where to reach out for help. diff --git a/docs/docs/usage/scaladoc/search-engine.md b/docs/docs/usage/scaladoc/search-engine.md index b338d38792a7..1bac1d37635d 100644 --- a/docs/docs/usage/scaladoc/search-engine.md +++ b/docs/docs/usage/scaladoc/search-engine.md @@ -83,4 +83,4 @@ Inkuire works as a JavaScript worker in the browser thanks to the power of [Scal To enable Inkuire when running scaladoc, add the flag `-Ygenerate-inkuire`. By adding this flag two files are generated: - `inkuire-db.json` - this is the file containing all the searchable declarations from the currently documented project in a format readable to the Inkuire search engine. -- `inkuire-config.json` - this file contains the locations of the database files that should be searchable from the documentation of the current project. By default, it will be generated with the location of the local db file as well as the default implied locations of database files in [External mappings](/scala3/guides/scaladoc/settings.html#-external-mappings). +- `inkuire-config.json` - this file contains the locations of the database files that should be searchable from the documentation of the current project. By default, it will be generated with the location of the local db file as well as the default implied locations of database files in [External mappings](https://docs.scala-lang.org/scala3/guides/scaladoc/settings.html#-external-mappings). diff --git a/project/CopyDocs.scala b/project/CopyDocs.scala index 5713f15e71ef..29760ce85e42 100644 --- a/project/CopyDocs.scala +++ b/project/CopyDocs.scala @@ -22,11 +22,11 @@ object CopyDocs { implicit def stringToFun(s: String): MyParams => String = _ => s // Patterns, for convenience - val titlePattern = "(?s)^---\n.*title: ([^\n]*).*---" - val jekyllLinkPattern = """\{\% link _overviews/scala3-scaladoc(.*) %\}""" + val titlePattern = "(?s)^---\n.*?title: ([^\n]*).*?---" + val jekyllLinkPattern = """\{\% link _overviews/scala3-reference(.*) %\}""" val jekyllLinkSubstitution = "..$1" - val jekyllLinkPattern2 = """\{\% link |_overviews/scala3-scaladoc/(.*) %\}""" - val jekyllLinkSubstitution2 = "$1" + val jekyllLinkPattern2 = """\{\% link _overviews/scala3-scaladoc(.*) %\}""" + val jekyllLinkSubstitution2 = ".$1" val localLinkPattern = """\((?!http|www)(.*).html\)""" val localLinkSubstitution = "($1.md)" @@ -44,6 +44,22 @@ object CopyDocs { * The inner set is a collection of pairs `regex pattern` -> `substitution value`. */ val transformationMap: Map[String, Set[(String, MyParams => String)]] = Map( + "docs/docs/usage/scaladoc/index.md" -> Set( + ("""\{\{ site\.baseurl \}\}/resources/images/scala3/scaladoc/logo\.svg""" -> "images/scaladoc-logo.png"), + ), + + "docs/docs/usage/scaladoc/site-versioning.md" -> Set( + ("""/resources/images/scala3/scaladoc/nightly\.gif""" -> "images/scaladoc/nightly.gif"), + ), + + "docs/docs/usage/scaladoc/search-engine.md" -> Set( + ("""/resources/images/scala3/scaladoc/inkuire-1\.0\.0-M2_js_flatMap\.gif""" -> "images/scaladoc/inkuire-1.0.0-M2_js_flatMap.gif"), + ), + + "docs/docs/reference/other-new-features/explicit-nulls.md" -> Set( + ("""/resources/images/scala3/explicit-nulls/explicit-nulls-type-hierarchy\.png""" -> "images/explicit-nulls/explicit-nulls-type-hierarchy.png"), + ), + "docs/docs/reference/" -> (commonTransformations + (titlePattern -> ((p) => s"---\nlayout: doc-page\ntitle: $$1\nmovedTo: https://docs.scala-lang.org/scala3/reference/${p.newPath}.html\n---")), ), @@ -57,7 +73,9 @@ object CopyDocs { ), "docs/docs/usage/tools-worksheets" -> (commonTransformations + - (titlePattern -> "---\nlayout: doc-page\ntitle: \"Worksheet mode with Dotty IDE\"\nmovedTo: https://docs.scala-lang.org/scala3/book/tools-worksheets.html\n---") + (titlePattern -> "---\nlayout: doc-page\ntitle: \"Worksheet mode with Dotty IDE\"\nmovedTo: https://docs.scala-lang.org/scala3/book/tools-worksheets.html\n---") + + ("""/resources/images/scala3-book/intellij-worksheet\.png""" -> "images/worksheets/intellij-worksheet.png") + + ("""/resources/images/scala3-book/metals-worksheet\.png""" -> "images/worksheets/metals-worksheet.png") ), "docs/docs/resources/talks" -> (commonTransformations + @@ -76,7 +94,7 @@ object CopyDocs { val fileContent = inputStream.getLines().mkString("\n") new PrintStream(newPath.toFile) { - val patterns = transformationMap.find { case (k, v) => path.toString.startsWith(k) }.map(_._2).getOrElse(Set.empty) + val patterns = transformationMap.filter { case (k, v) => path.toString.startsWith(k) }.flatMap(_._2) val params = MyParams(newPath = s.stripPrefix("docs/docs/reference/").stripSuffix(".md")) val transformed = patterns.foldLeft(fileContent) { case (res, (pattern, substitution)) => res.replaceAll(pattern, substitution(params)) } write(transformed.getBytes("UTF8")) diff --git a/project/scripts/genDocsScalaLang b/project/scripts/genDocsScalaLang index a59cc4509fd9..40703bc0dac7 100755 --- a/project/scripts/genDocsScalaLang +++ b/project/scripts/genDocsScalaLang @@ -41,10 +41,3 @@ cp -f "$PWD/docs/docsScalaLangResources/scaladoc-assets.html" "$DOCS_SCALA_LANG_ # Hack inclusion of these assests by the docs.scala-lang jekyll builder echo "{% include scaladoc-assets.html %}" >> "$DOCS_SCALA_LANG_DIR/_layouts/inner-page-parent-dropdown.html" - -# Push changes to fork branch -cd $DOCS_SCALA_LANG_DIR -git remote add barkingbad git@github.com:BarkingBad/docs.scala-lang.git -git add . -git commit -m "Update docs from dotty repo" -git push -f barkingbad main:pregenerated-page From a59db44734663b8c8fee0bb6334612e6f599b64a Mon Sep 17 00:00:00 2001 From: Andrzej Ratajczak Date: Tue, 5 Oct 2021 12:13:45 +0200 Subject: [PATCH 0730/1244] Fix publishing nightly docs do BarkingBad fork. --- .github/workflows/ci.yaml | 2 +- project/scripts/genDocsScalaLang | 16 +++++++++++++++- .../dotty/tools/scaladoc/ScaladocSettings.scala | 2 +- .../scaladoc/site/FrontMatterRenderer.scala | 8 ++++++-- .../tools/scaladoc/site/LoadedTemplate.scala | 8 +------- .../dotty/tools/scaladoc/site/templates.scala | 13 +++++++++++-- 6 files changed, 35 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 24d04be110f5..037229da32fc 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -514,7 +514,7 @@ jobs: with: personal_token: ${{ DOCS_SCALALANG_BOT_TOKEN }} publish_dir: docsScalaLang - external_repository: scala/docs.scala-lang + external_repository: BarkingBad/docs.scala-lang publish_branch: dev publish_release: diff --git a/project/scripts/genDocsScalaLang b/project/scripts/genDocsScalaLang index 40703bc0dac7..1404cd5ef0f7 100755 --- a/project/scripts/genDocsScalaLang +++ b/project/scripts/genDocsScalaLang @@ -18,8 +18,22 @@ git clone "https://github.com/scala/docs.scala-lang.git" $DOCS_SCALA_LANG_DIR SBT="$SCRIPT_DIR/sbt" mkdir -pv $SITE_OUT_DIR + env "scaladoc.projectFormat=md" "$SBT" "scaladoc/renderScaladocScalajsToFile $DOCS_SCALA_LANG_DIR/scripts/scaladoc-scalajs.js $DOCS_SCALA_LANG_DIR/resources/css code-snippets.css" -"bin/scaladoc" "-d" "$SITE_OUT_DIR" "-format" "md" "-siteroot" "docs" "/dev/null" + +DOTTY_NONBOOTSTRAPPED_VERSION_COMMAND="$SBT \"eval println(Build.dottyNonBootstrappedVersion)\"" +DOTTY_NONBOOTSTRAPPED_VERSION=$(eval $DOTTY_NONBOOTSTRAPPED_VERSION_COMMAND | tail -n 2 | head -n 1) + +DOTTY_BOOTSTRAPPED_VERSION_COMMAND="$SBT \"eval println(Build.dottyVersion)\"" +DOTTY_BOOTSTRAPPED_VERSION=$(eval $DOTTY_BOOTSTRAPPED_VERSION_COMMAND | tail -n 2 | head -n 1) + +GITHUB_REPOSITORY="lampepfl/dotty" +GITHUB_SHA="3.0.0" + +"bin/scaladoc" "-d" "$SITE_OUT_DIR" "-format" "md" "-siteroot" "docs" "/dev/null " \ + -source-links:out/bootstrap/stdlib-bootstrapped/scala-"${DOTTY_NONBOOTSTRAPPED_VERSION}"/src_managed/main/scala-library-src=github://scala/scala/v"${STDLIB_VERSION}"#src/library \ + -source-links:out/bootstrap/stdlib-bootstrapped/scala-"${DOTTY_NONBOOTSTRAPPED_VERSION}"/src_managed/main/dotty-library-src=github://"${GITHUB_REPOSITORY}"/"${GITHUB_SHA}"\#library/src \ + -source-links:github://"${GITHUB_REPOSITORY}"/"${GITHUB_SHA}" \ if [ ! -d "$SITE_OUT_DIR" ]; then echo "Output directory did not exist: $SITE_OUT_DIR" 1>&2 diff --git a/scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala b/scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala index ba077d31a8fd..4697783de20c 100644 --- a/scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala +++ b/scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala @@ -128,7 +128,7 @@ class ScaladocSettings extends SettingGroup with AllScalaSettings: val scastieConfiguration: Setting[String] = StringSetting("-scastie-configuration", "Scastie configuration", "Additional configuration passed to Scastie in code snippets", "") - + val projectFormat: Setting[String] = ChoiceSetting( "-format", diff --git a/scaladoc/src/dotty/tools/scaladoc/site/FrontMatterRenderer.scala b/scaladoc/src/dotty/tools/scaladoc/site/FrontMatterRenderer.scala index dde7650a9480..2e02918b5b39 100644 --- a/scaladoc/src/dotty/tools/scaladoc/site/FrontMatterRenderer.scala +++ b/scaladoc/src/dotty/tools/scaladoc/site/FrontMatterRenderer.scala @@ -14,7 +14,11 @@ object FrontMatterRenderer: val rows = renderProperties(properties) ++ renderProperties(properties("page").asInstanceOf[Map[String, Object]]) - rows.mkString("---\n", "\n", "\n---") + "\n\n\n\n" + rows.mkString("---\n", "\n", "\n---") + "\n\n\n\n" + diff --git a/scaladoc/src/dotty/tools/scaladoc/site/LoadedTemplate.scala b/scaladoc/src/dotty/tools/scaladoc/site/LoadedTemplate.scala index f7623d79c7c0..3a7ba6c98d07 100644 --- a/scaladoc/src/dotty/tools/scaladoc/site/LoadedTemplate.scala +++ b/scaladoc/src/dotty/tools/scaladoc/site/LoadedTemplate.scala @@ -40,15 +40,9 @@ case class LoadedTemplate( def resolveToHtml(ctx: StaticSiteContext): ResolvedPage = val posts = children.map(_.lazyTemplateProperties(ctx)) def getMap(key: String) = templateFile.settings.getOrElse(key, Map.empty).asInstanceOf[Map[String, Object]] - val sourceLinks = if !file.exists() then Nil else - // TODO (https://github.com/lampepfl/scala3doc/issues/240): configure source root - // toRealPath is used to turn symlinks into proper paths - val actualPath = Paths.get("").toAbsolutePath.relativize(file.toPath.toRealPath()) - ctx.sourceLinks.pathTo(actualPath).map("viewSource" -> _ ) ++ - ctx.sourceLinks.pathTo(actualPath, operation = "edit", optionalRevision = Some("master")).map("editSource" -> _ ) val updatedSettings = templateFile.settings ++ ctx.projectWideProperties + - ("site" -> (getMap("site") + ("posts" -> posts))) + ("urls" -> sourceLinks.toMap) + + ("site" -> (getMap("site") + ("posts" -> posts))) + ("page" -> (getMap("page") + ("title" -> templateFile.title.name))) templateFile.resolveInner(RenderingContext(updatedSettings, ctx.layouts))(using ctx) diff --git a/scaladoc/src/dotty/tools/scaladoc/site/templates.scala b/scaladoc/src/dotty/tools/scaladoc/site/templates.scala index 22755290840e..3149023d3613 100644 --- a/scaladoc/src/dotty/tools/scaladoc/site/templates.scala +++ b/scaladoc/src/dotty/tools/scaladoc/site/templates.scala @@ -114,7 +114,15 @@ case class TemplateFile( val rendered = ssctx.args.projectFormat match case "html" => Template.parse(this.rawCode).`with`(tag).render(mutableProperties) case "md" => this.rawCode - + + val sourceLinks = if !file.exists() then Nil else + // TODO (https://github.com/lampepfl/scala3doc/issues/240): configure source root + // toRealPath is used to turn symlinks into proper paths + val actualPath = Paths.get("").toAbsolutePath.relativize(file.toPath.toRealPath()) + ssctx.sourceLinks.pathTo(actualPath).map("viewSource" -> _ ) ++ + // List("editSource" -> ssctx.sourceLinks.pathTo(actualPath)) + ssctx.sourceLinks.pathTo(actualPath, operation = "edit", optionalRevision = Some("master")).map("editSource" -> _ ) + // We want to render markdown only if next template is html val code = if (isHtml || layoutTemplate.exists(!_.isHtml)) rendered else // Snippet compiler currently supports markdown only @@ -125,7 +133,8 @@ case class TemplateFile( ssctx.args.projectFormat match case "html" => HtmlRenderer.builder(defaultMarkdownOptions).build().render(processed) case "md" => - FrontMatterRenderer.render(settings) + + + FrontMatterRenderer.render(settings + ("urls" -> sourceLinks.toMap)) + Formatter.builder(defaultMarkdownOptions).build().render(processed) From 9a84b7032fa7ce520a82d4e729b4b55d88a52a68 Mon Sep 17 00:00:00 2001 From: Andrzej Ratajczak Date: Thu, 14 Oct 2021 15:41:59 +0200 Subject: [PATCH 0731/1244] Fix docs and resources copying --- docs/docs/reference/changed-features.md | 4 +- .../changed-features/compiler-plugins.md | 2 +- .../changed-features/eta-expansion.md | 2 +- .../changed-features/implicit-conversions.md | 2 +- .../changed-features/implicit-resolution.md | 2 +- .../reference/changed-features/imports.md | 2 +- .../changed-features/lazy-vals-init.md | 2 +- .../changed-features/main-functions.md | 2 +- .../changed-features/match-syntax.md | 2 +- .../changed-features/numeric-literals.md | 4 +- .../reference/changed-features/operators.md | 2 +- .../changed-features/overload-resolution.md | 2 +- .../changed-features/pattern-bindings.md | 2 +- .../changed-features/pattern-matching.md | 2 +- .../changed-features/structural-types.md | 2 +- .../changed-features/type-checking.md | 2 +- .../changed-features/type-inference.md | 2 +- .../changed-features/vararg-splices.md | 2 +- .../reference/changed-features/wildcards.md | 4 +- docs/docs/reference/dropped-features.md | 2 +- .../reference/dropped-features/auto-apply.md | 2 +- .../dropped-features/class-shadowing.md | 2 +- .../dropped-features/delayed-init.md | 2 +- .../reference/dropped-features/do-while.md | 2 +- .../dropped-features/early-initializers.md | 2 +- .../dropped-features/existential-types.md | 2 +- .../reference/dropped-features/limit22.md | 2 +- .../docs/reference/dropped-features/macros.md | 2 +- .../dropped-features/package-objects.md | 2 +- .../dropped-features/procedure-syntax.md | 2 +- .../reference/dropped-features/symlits.md | 2 +- .../dropped-features/this-qualifier.md | 2 +- .../dropped-features/type-projection.md | 2 +- .../dropped-features/weak-conformance.md | 2 +- .../dropped-features/wildcard-init.md | 2 +- docs/docs/reference/dropped-features/xml.md | 2 +- docs/docs/reference/language-versions.md | 2 +- .../other-new-features/experimental-defs.md | 6 +- .../reference/other-new-features/type-test.md | 2 +- docs/docs/reference/syntax.md | 2 +- docs/docs/resources/talks.md | 69 ------- docs/docs/usage/getting-started.md | 193 ------------------ docs/docs/usage/tools-worksheets.md | 56 ----- .../scaladoc/inkuire-1.0.0-M2_js_flatMap.gif | Bin 0 -> 352175 bytes docs/sidebar.yml | 5 - project/CopyDocs.scala | 16 +- project/scripts/genDocsScalaLang | 11 +- .../dotty/tools/scaladoc/site/templates.scala | 6 +- 48 files changed, 56 insertions(+), 390 deletions(-) delete mode 100644 docs/docs/resources/talks.md delete mode 100644 docs/docs/usage/getting-started.md delete mode 100644 docs/docs/usage/tools-worksheets.md create mode 100644 docs/images/scaladoc/inkuire-1.0.0-M2_js_flatMap.gif diff --git a/docs/docs/reference/changed-features.md b/docs/docs/reference/changed-features.md index c23a9031bef0..7a8f717f2394 100644 --- a/docs/docs/reference/changed-features.md +++ b/docs/docs/reference/changed-features.md @@ -1,8 +1,8 @@ --- title: "Other Changed Features" type: chapter -num: 51 -previous-page: /scala3/reference/other-new-features/type-test +num: 52 +previous-page: /scala3/reference/other-new-features/experimental-defs next-page: /scala3/reference/changed-features/numeric-literals --- diff --git a/docs/docs/reference/changed-features/compiler-plugins.md b/docs/docs/reference/changed-features/compiler-plugins.md index c77796d71df1..b8e108c560c4 100644 --- a/docs/docs/reference/changed-features/compiler-plugins.md +++ b/docs/docs/reference/changed-features/compiler-plugins.md @@ -1,7 +1,7 @@ --- title: "Changes in Compiler Plugins" type: section -num: 67 +num: 68 previous-page: /scala3/reference/changed-features/eta-expansion next-page: /scala3/reference/changed-features/lazy-vals-init --- diff --git a/docs/docs/reference/changed-features/eta-expansion.md b/docs/docs/reference/changed-features/eta-expansion.md index 91516edca5a5..f21cb54406ad 100644 --- a/docs/docs/reference/changed-features/eta-expansion.md +++ b/docs/docs/reference/changed-features/eta-expansion.md @@ -1,7 +1,7 @@ --- title: "Automatic Eta Expansion" type: section -num: 66 +num: 67 previous-page: /scala3/reference/changed-features/pattern-matching next-page: /scala3/reference/changed-features/compiler-plugins --- diff --git a/docs/docs/reference/changed-features/implicit-conversions.md b/docs/docs/reference/changed-features/implicit-conversions.md index 39b4cde31e63..aab1baa32373 100644 --- a/docs/docs/reference/changed-features/implicit-conversions.md +++ b/docs/docs/reference/changed-features/implicit-conversions.md @@ -1,7 +1,7 @@ --- title: "Implicit Conversions" type: section -num: 60 +num: 61 previous-page: /scala3/reference/changed-features/implicit-resolution next-page: /scala3/reference/changed-features/overload-resolution --- diff --git a/docs/docs/reference/changed-features/implicit-resolution.md b/docs/docs/reference/changed-features/implicit-resolution.md index 410784834f95..2a563aceeb19 100644 --- a/docs/docs/reference/changed-features/implicit-resolution.md +++ b/docs/docs/reference/changed-features/implicit-resolution.md @@ -1,7 +1,7 @@ --- title: "Changes in Implicit Resolution" type: section -num: 59 +num: 60 previous-page: /scala3/reference/changed-features/type-inference next-page: /scala3/reference/changed-features/implicit-conversions --- diff --git a/docs/docs/reference/changed-features/imports.md b/docs/docs/reference/changed-features/imports.md index 39568769a270..e46fbc8fc44b 100644 --- a/docs/docs/reference/changed-features/imports.md +++ b/docs/docs/reference/changed-features/imports.md @@ -1,7 +1,7 @@ --- title: "Imports" type: section -num: 56 +num: 57 previous-page: /scala3/reference/changed-features/wildcards next-page: /scala3/reference/changed-features/type-checking --- diff --git a/docs/docs/reference/changed-features/lazy-vals-init.md b/docs/docs/reference/changed-features/lazy-vals-init.md index a065cebb2a49..f70ec622f6e1 100644 --- a/docs/docs/reference/changed-features/lazy-vals-init.md +++ b/docs/docs/reference/changed-features/lazy-vals-init.md @@ -1,7 +1,7 @@ --- title: Lazy Vals Initialization type: section -num: 68 +num: 69 previous-page: /scala3/reference/changed-features/compiler-plugins next-page: /scala3/reference/changed-features/main-functions --- diff --git a/docs/docs/reference/changed-features/main-functions.md b/docs/docs/reference/changed-features/main-functions.md index 6f035278ed05..777532e7110b 100644 --- a/docs/docs/reference/changed-features/main-functions.md +++ b/docs/docs/reference/changed-features/main-functions.md @@ -1,7 +1,7 @@ --- title: "Main Methods" type: section -num: 69 +num: 70 previous-page: /scala3/reference/changed-features/lazy-vals-init next-page: /scala3/reference/dropped-features --- diff --git a/docs/docs/reference/changed-features/match-syntax.md b/docs/docs/reference/changed-features/match-syntax.md index 7ebc85b6d003..12e35cfa94df 100644 --- a/docs/docs/reference/changed-features/match-syntax.md +++ b/docs/docs/reference/changed-features/match-syntax.md @@ -1,7 +1,7 @@ --- title: "Match Expressions" type: section -num: 62 +num: 63 previous-page: /scala3/reference/changed-features/overload-resolution next-page: /scala3/reference/changed-features/vararg-splices --- diff --git a/docs/docs/reference/changed-features/numeric-literals.md b/docs/docs/reference/changed-features/numeric-literals.md index 8a21d97bd4a4..1cc07e3b1c8e 100644 --- a/docs/docs/reference/changed-features/numeric-literals.md +++ b/docs/docs/reference/changed-features/numeric-literals.md @@ -1,9 +1,9 @@ --- title: "Numeric Literals" type: section -num: 52 +num: 53 previous-page: /scala3/reference/changed-features next-page: /scala3/reference/changed-features/structural-types --- -[Document was moved](../experimental/numeric-literals.md) \ No newline at end of file +[Document was moved](../experimental/numeric-literals.md) diff --git a/docs/docs/reference/changed-features/operators.md b/docs/docs/reference/changed-features/operators.md index 5e05c6bfbcae..953aa18c8408 100644 --- a/docs/docs/reference/changed-features/operators.md +++ b/docs/docs/reference/changed-features/operators.md @@ -1,7 +1,7 @@ --- title: "Rules for Operators" type: section -num: 54 +num: 55 previous-page: /scala3/reference/changed-features/structural-types next-page: /scala3/reference/changed-features/wildcards --- diff --git a/docs/docs/reference/changed-features/overload-resolution.md b/docs/docs/reference/changed-features/overload-resolution.md index 6b203299707f..4205acdd412f 100644 --- a/docs/docs/reference/changed-features/overload-resolution.md +++ b/docs/docs/reference/changed-features/overload-resolution.md @@ -1,7 +1,7 @@ --- title: "Changes in Overload Resolution" type: section -num: 61 +num: 62 previous-page: /scala3/reference/changed-features/implicit-conversions next-page: /scala3/reference/changed-features/match-syntax --- diff --git a/docs/docs/reference/changed-features/pattern-bindings.md b/docs/docs/reference/changed-features/pattern-bindings.md index 307ff6387cce..a5eb39e98da6 100644 --- a/docs/docs/reference/changed-features/pattern-bindings.md +++ b/docs/docs/reference/changed-features/pattern-bindings.md @@ -1,7 +1,7 @@ --- title: "Pattern Bindings" type: section -num: 64 +num: 65 previous-page: /scala3/reference/changed-features/vararg-splices next-page: /scala3/reference/changed-features/pattern-matching --- diff --git a/docs/docs/reference/changed-features/pattern-matching.md b/docs/docs/reference/changed-features/pattern-matching.md index 2216d145a80d..93712f004307 100644 --- a/docs/docs/reference/changed-features/pattern-matching.md +++ b/docs/docs/reference/changed-features/pattern-matching.md @@ -1,7 +1,7 @@ --- title: "Option-less pattern matching" type: section -num: 65 +num: 66 previous-page: /scala3/reference/changed-features/pattern-bindings next-page: /scala3/reference/changed-features/eta-expansion --- diff --git a/docs/docs/reference/changed-features/structural-types.md b/docs/docs/reference/changed-features/structural-types.md index fe20a3aa5483..3ce3d6ac88bd 100644 --- a/docs/docs/reference/changed-features/structural-types.md +++ b/docs/docs/reference/changed-features/structural-types.md @@ -1,7 +1,7 @@ --- title: "Programmatic Structural Types" type: section -num: 53 +num: 54 previous-page: /scala3/reference/changed-features/numeric-literals next-page: /scala3/reference/changed-features/operators --- diff --git a/docs/docs/reference/changed-features/type-checking.md b/docs/docs/reference/changed-features/type-checking.md index 81ca345a6c7e..f647e57ac462 100644 --- a/docs/docs/reference/changed-features/type-checking.md +++ b/docs/docs/reference/changed-features/type-checking.md @@ -1,7 +1,7 @@ --- title: "Changes in Type Checking" type: section -num: 57 +num: 58 previous-page: /scala3/reference/changed-features/imports next-page: /scala3/reference/changed-features/type-inference --- diff --git a/docs/docs/reference/changed-features/type-inference.md b/docs/docs/reference/changed-features/type-inference.md index 873c91831210..2432cb8e4339 100644 --- a/docs/docs/reference/changed-features/type-inference.md +++ b/docs/docs/reference/changed-features/type-inference.md @@ -1,7 +1,7 @@ --- title: "Changes in Type Inference" type: section -num: 58 +num: 59 previous-page: /scala3/reference/changed-features/type-checking next-page: /scala3/reference/changed-features/implicit-resolution --- diff --git a/docs/docs/reference/changed-features/vararg-splices.md b/docs/docs/reference/changed-features/vararg-splices.md index efa7f034acea..2da55ee79945 100644 --- a/docs/docs/reference/changed-features/vararg-splices.md +++ b/docs/docs/reference/changed-features/vararg-splices.md @@ -1,7 +1,7 @@ --- title: "Vararg Splices" type: section -num: 63 +num: 64 previous-page: /scala3/reference/changed-features/match-syntax next-page: /scala3/reference/changed-features/pattern-bindings --- diff --git a/docs/docs/reference/changed-features/wildcards.md b/docs/docs/reference/changed-features/wildcards.md index fdf69fdcd954..0a84ebbf2a48 100644 --- a/docs/docs/reference/changed-features/wildcards.md +++ b/docs/docs/reference/changed-features/wildcards.md @@ -1,7 +1,7 @@ --- title: Wildcard Arguments in Types type: section -num: 55 +num: 56 previous-page: /scala3/reference/changed-features/operators next-page: /scala3/reference/changed-features/imports --- @@ -49,4 +49,4 @@ These rules make it possible to cross build between Scala 2 using the kind proje There is also a migration path for users that want a one-time transition to syntax with `_` as a type parameter placeholder. With option `-Ykind-projector:underscores` Scala 3 will regard `_` as a type parameter placeholder, leaving `?` as the only syntax for wildcards. -To cross-compile with old Scala 2 sources, while using `_` a placeholder, you must use options `-Xsource:3 -P:kind-projector:underscore-placeholders` together with a recent version of kind-projector (`0.13` and higher) and most recent versions of Scala 2 (`2.13.5` and higher and `2.12.14` and higher) +To cross-compile with old Scala 2 sources, while using `_` a placeholder, you must use options `-Xsource:3 -P:kind-projector:underscore-placeholders` together with a recent version of kind-projector (`0.13` and higher) and most recent versions of Scala 2 (`2.13.5` and higher and `2.12.14` and higher) diff --git a/docs/docs/reference/dropped-features.md b/docs/docs/reference/dropped-features.md index b2fb1fbe9fe2..6ccff5c40425 100644 --- a/docs/docs/reference/dropped-features.md +++ b/docs/docs/reference/dropped-features.md @@ -1,7 +1,7 @@ --- title: "Dropped Features" type: chapter -num: 70 +num: 71 previous-page: /scala3/reference/changed-features/main-functions next-page: /scala3/reference/dropped-features/delayed-init --- diff --git a/docs/docs/reference/dropped-features/auto-apply.md b/docs/docs/reference/dropped-features/auto-apply.md index 8670850f7903..6696bd8165d8 100644 --- a/docs/docs/reference/dropped-features/auto-apply.md +++ b/docs/docs/reference/dropped-features/auto-apply.md @@ -1,7 +1,7 @@ --- title: "Dropped: Auto-Application" type: section -num: 83 +num: 84 previous-page: /scala3/reference/dropped-features/symlits next-page: /scala3/reference/dropped-features/weak-conformance --- diff --git a/docs/docs/reference/dropped-features/class-shadowing.md b/docs/docs/reference/dropped-features/class-shadowing.md index b3a4ab2dc1ad..50101bf1d0b4 100644 --- a/docs/docs/reference/dropped-features/class-shadowing.md +++ b/docs/docs/reference/dropped-features/class-shadowing.md @@ -1,7 +1,7 @@ --- title: "Dropped: Class Shadowing" type: section -num: 79 +num: 80 previous-page: /scala3/reference/dropped-features/early-initializers next-page: /scala3/reference/dropped-features/limit22 --- diff --git a/docs/docs/reference/dropped-features/delayed-init.md b/docs/docs/reference/dropped-features/delayed-init.md index 5673db5dfb8e..f0b65a242c1a 100644 --- a/docs/docs/reference/dropped-features/delayed-init.md +++ b/docs/docs/reference/dropped-features/delayed-init.md @@ -1,7 +1,7 @@ --- title: "Dropped: DelayedInit" type: section -num: 71 +num: 72 previous-page: /scala3/reference/dropped-features next-page: /scala3/reference/dropped-features/macros --- diff --git a/docs/docs/reference/dropped-features/do-while.md b/docs/docs/reference/dropped-features/do-while.md index 3fd59430ac3b..7bc3b73e0091 100644 --- a/docs/docs/reference/dropped-features/do-while.md +++ b/docs/docs/reference/dropped-features/do-while.md @@ -1,7 +1,7 @@ --- title: "Dropped: Do-While" type: section -num: 75 +num: 76 previous-page: /scala3/reference/dropped-features/type-projection next-page: /scala3/reference/dropped-features/procedure-syntax --- diff --git a/docs/docs/reference/dropped-features/early-initializers.md b/docs/docs/reference/dropped-features/early-initializers.md index 18d97640b12f..234de159c30c 100644 --- a/docs/docs/reference/dropped-features/early-initializers.md +++ b/docs/docs/reference/dropped-features/early-initializers.md @@ -1,7 +1,7 @@ --- title: "Dropped: Early Initializers" type: section -num: 78 +num: 79 previous-page: /scala3/reference/dropped-features/package-objects next-page: /scala3/reference/dropped-features/class-shadowing --- diff --git a/docs/docs/reference/dropped-features/existential-types.md b/docs/docs/reference/dropped-features/existential-types.md index df624cbd0721..ea176659fd77 100644 --- a/docs/docs/reference/dropped-features/existential-types.md +++ b/docs/docs/reference/dropped-features/existential-types.md @@ -1,7 +1,7 @@ --- title: "Dropped: Existential Types" type: section -num: 73 +num: 74 previous-page: /scala3/reference/dropped-features/macros next-page: /scala3/reference/dropped-features/type-projection --- diff --git a/docs/docs/reference/dropped-features/limit22.md b/docs/docs/reference/dropped-features/limit22.md index 2e21efec58f6..1c2bb0e2882a 100644 --- a/docs/docs/reference/dropped-features/limit22.md +++ b/docs/docs/reference/dropped-features/limit22.md @@ -1,7 +1,7 @@ --- title: "Dropped: Limit 22" type: section -num: 80 +num: 81 previous-page: /scala3/reference/dropped-features/class-shadowing next-page: /scala3/reference/dropped-features/xml --- diff --git a/docs/docs/reference/dropped-features/macros.md b/docs/docs/reference/dropped-features/macros.md index f7a23edb0057..8208e8ee630c 100644 --- a/docs/docs/reference/dropped-features/macros.md +++ b/docs/docs/reference/dropped-features/macros.md @@ -1,7 +1,7 @@ --- title: "Dropped: Scala 2 Macros" type: section -num: 72 +num: 73 previous-page: /scala3/reference/dropped-features/delayed-init next-page: /scala3/reference/dropped-features/existential-types --- diff --git a/docs/docs/reference/dropped-features/package-objects.md b/docs/docs/reference/dropped-features/package-objects.md index d9099eef9805..12004c37dea3 100644 --- a/docs/docs/reference/dropped-features/package-objects.md +++ b/docs/docs/reference/dropped-features/package-objects.md @@ -1,7 +1,7 @@ --- title: "Dropped: Package Objects" type: section -num: 77 +num: 78 previous-page: /scala3/reference/dropped-features/procedure-syntax next-page: /scala3/reference/dropped-features/early-initializers --- diff --git a/docs/docs/reference/dropped-features/procedure-syntax.md b/docs/docs/reference/dropped-features/procedure-syntax.md index f3bf8cc9d47f..d7a33cf374f8 100644 --- a/docs/docs/reference/dropped-features/procedure-syntax.md +++ b/docs/docs/reference/dropped-features/procedure-syntax.md @@ -1,7 +1,7 @@ --- title: "Dropped: Procedure Syntax" type: section -num: 76 +num: 77 previous-page: /scala3/reference/dropped-features/do-while next-page: /scala3/reference/dropped-features/package-objects --- diff --git a/docs/docs/reference/dropped-features/symlits.md b/docs/docs/reference/dropped-features/symlits.md index 3cb7243af964..1c71608f40fa 100644 --- a/docs/docs/reference/dropped-features/symlits.md +++ b/docs/docs/reference/dropped-features/symlits.md @@ -1,7 +1,7 @@ --- title: "Dropped: Symbol Literals" type: section -num: 82 +num: 83 previous-page: /scala3/reference/dropped-features/xml next-page: /scala3/reference/dropped-features/auto-apply --- diff --git a/docs/docs/reference/dropped-features/this-qualifier.md b/docs/docs/reference/dropped-features/this-qualifier.md index c25f896415f5..69906351ca67 100644 --- a/docs/docs/reference/dropped-features/this-qualifier.md +++ b/docs/docs/reference/dropped-features/this-qualifier.md @@ -1,7 +1,7 @@ --- title: "Dropped: private[this] and protected[this]" type: section -num: 85 +num: 86 previous-page: /scala3/reference/dropped-features/weak-conformance next-page: /scala3/reference/dropped-features/wildcard-init --- diff --git a/docs/docs/reference/dropped-features/type-projection.md b/docs/docs/reference/dropped-features/type-projection.md index fb87ef79be23..f2d2f215ed21 100644 --- a/docs/docs/reference/dropped-features/type-projection.md +++ b/docs/docs/reference/dropped-features/type-projection.md @@ -1,7 +1,7 @@ --- title: "Dropped: General Type Projection" type: section -num: 74 +num: 75 previous-page: /scala3/reference/dropped-features/existential-types next-page: /scala3/reference/dropped-features/do-while --- diff --git a/docs/docs/reference/dropped-features/weak-conformance.md b/docs/docs/reference/dropped-features/weak-conformance.md index deca70b60714..1b6db185fad8 100644 --- a/docs/docs/reference/dropped-features/weak-conformance.md +++ b/docs/docs/reference/dropped-features/weak-conformance.md @@ -1,7 +1,7 @@ --- title: "Dropped: Weak Conformance" type: section -num: 84 +num: 85 previous-page: /scala3/reference/dropped-features/auto-apply next-page: /scala3/reference/dropped-features/this-qualifier --- diff --git a/docs/docs/reference/dropped-features/wildcard-init.md b/docs/docs/reference/dropped-features/wildcard-init.md index be633fb1ca21..078ec138b3bb 100644 --- a/docs/docs/reference/dropped-features/wildcard-init.md +++ b/docs/docs/reference/dropped-features/wildcard-init.md @@ -1,7 +1,7 @@ --- title: "Dropped: Wildcard Initializer" type: section -num: 86 +num: 87 previous-page: /scala3/reference/dropped-features/this-qualifier next-page: /scala3/reference/syntax --- diff --git a/docs/docs/reference/dropped-features/xml.md b/docs/docs/reference/dropped-features/xml.md index cab3d0663a55..c094408909f4 100644 --- a/docs/docs/reference/dropped-features/xml.md +++ b/docs/docs/reference/dropped-features/xml.md @@ -1,7 +1,7 @@ --- title: "Dropped: XML Literals" type: section -num: 81 +num: 82 previous-page: /scala3/reference/dropped-features/limit22 next-page: /scala3/reference/dropped-features/symlits --- diff --git a/docs/docs/reference/language-versions.md b/docs/docs/reference/language-versions.md index ec16e8bed3cc..a17a567d7362 100644 --- a/docs/docs/reference/language-versions.md +++ b/docs/docs/reference/language-versions.md @@ -2,7 +2,7 @@ title: "Language Versions" type: chapter description: This page lists the different flavours of language supported by the Scala 3 compiler. -num: 100 +num: 101 previous-page: overview --- diff --git a/docs/docs/reference/other-new-features/experimental-defs.md b/docs/docs/reference/other-new-features/experimental-defs.md index 11121f1d0fcd..5060ffb889d5 100644 --- a/docs/docs/reference/other-new-features/experimental-defs.md +++ b/docs/docs/reference/other-new-features/experimental-defs.md @@ -1,8 +1,12 @@ --- -layout: doc-page title: "Experimental definitions" +type: section +num: 51 +previous-page: /scala3/reference/other-new-features/type-test +next-page: /scala3/reference/changed-features --- + ## Experimental definitions The `@experimental` annotation allows the definition of an API that is not guaranteed backward binary or source compatibility. diff --git a/docs/docs/reference/other-new-features/type-test.md b/docs/docs/reference/other-new-features/type-test.md index 1fab03490e98..62b8d59eec6d 100644 --- a/docs/docs/reference/other-new-features/type-test.md +++ b/docs/docs/reference/other-new-features/type-test.md @@ -3,7 +3,7 @@ title: "TypeTest" type: section num: 50 previous-page: /scala3/reference/other-new-features/safe-initialization -next-page: /scala3/reference/changed-features +next-page: /scala3/reference/other-new-features/experimental-defs --- ## TypeTest diff --git a/docs/docs/reference/syntax.md b/docs/docs/reference/syntax.md index 5bb53ddac00b..4561ad7c91b6 100644 --- a/docs/docs/reference/syntax.md +++ b/docs/docs/reference/syntax.md @@ -1,7 +1,7 @@ --- title: "Scala 3 Syntax Summary" type: chapter -num: 87 +num: 88 previous-page: /scala3/reference/dropped-features/wildcard-init --- diff --git a/docs/docs/resources/talks.md b/docs/docs/resources/talks.md deleted file mode 100644 index 9991d847fb9a..000000000000 --- a/docs/docs/resources/talks.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -layout: singlepage-overview -title: "Talks" ---- - -Let’s Talk About Scala 3 Series -------------------------------- - -[Let’s Talk About Scala 3](https://www.youtube.com/playlist?list=PLTx-VKTe8yLxYQfX_eGHCxaTuWvvG28Ml) is a series -of short (around 15 min) talks about Scala 3. It covers a variety of themes like how to get started, how to take -advantage of the new language features, or how to migrate from Scala 2. - -Talks on Scala 3 ----------------- -- (ScalaDays 2019, Lausanne) [A Tour of Scala 3](https://www.youtube.com/watch?v=_Rnrx2lo9cw) by [Martin Odersky](http://twitter.com/odersky) [\[slides\]](https://www.slideshare.net/Odersky/a-tour-of-scala-3) - -- (ScalaDays 2016, Berlin) [Scala's Road Ahead](https://www.youtube.com/watch?v=GHzWqJKFCk4) by [Martin Odersky](http://twitter.com/odersky) [\[slides\]](http://www.slideshare.net/Odersky/scala-days-nyc-2016) - -- (JVMLS 2015) [Compilers are Databases](https://www.youtube.com/watch?v=WxyyJyB_Ssc) by [Martin Odersky](http://twitter.com/odersky) [\[slides\]](http://www.slideshare.net/Odersky/compilers-are-databases) - -- (Scala World 2015) [Dotty: Exploring the future of Scala](https://www.youtube.com/watch?v=aftdOFuVU1o) by [Dmitry Petrashko](http://twitter.com/darkdimius) [\[slides\]](https://d-d.me/scalaworld2015/#/). - Dmitry covers many of the new features that Dotty brings on the table such as Intersection and Union types, improved lazy val initialization and more. - Dmitry also covers dotty internals and in particular the high-level of contextual abstractions of Dotty. You will get to - become familiar with many core concepts such as `Denotations`, their evolution through (compilation) time, their - transformations and more. - -Deep Dive with Scala 3 ----------------------- -- (ScalaDays 2019, Lausanne) [Metaprogramming in Dotty](https://www.youtube.com/watch?v=ZfDS_gJyPTc) by [Nicolas Stucki](https://github.com/nicolasstucki). - -- (ScalaDays 2019, Lausanne) [Future-proofing Scala: the TASTY intermediate representation](https://www.youtube.com/watch?v=zQFjC3zLYwo) by [Guillaume Martres](http://guillaume.martres.me/). - -- (Mar 21, 2017) [Dotty Internals 1: Trees & Symbols](https://www.youtube.com/watch?v=yYd-zuDd3S8) by [Dmitry Petrashko](http://twitter.com/darkdimius) [\[meeting notes\]](https://dotty.epfl.ch/docs/internals/dotty-internals-1-notes.html). - This is a recorded meeting between EPFL and Waterloo, where we introduce first notions inside Dotty: Trees and Symbols. - -- (Mar 21, 2017) [Dotty Internals 2: Types](https://www.youtube.com/watch?v=3gmLIYlGbKc) by [Martin Odersky](http://twitter.com/odersky) and [Dmitry Petrashko](http://twitter.com/darkdimius). - This is a recorded meeting between EPFL and Waterloo, where we introduce how types are represented inside Dotty. - -- (Jun 15, 2017) [Dotty Internals 3: Denotations](https://youtu.be/9iPA7zMRGKY) by [Martin Odersky](http://twitter.com/odersky) and [Dmitry Petrashko](http://twitter.com/darkdimius). - This is a recorded meeting between EPFL and Waterloo, where we introduce denotations in Dotty. - -- (JVM Language Summit) [How do we make the Dotty compiler fast](https://www.youtube.com/watch?v=9xYoSwnSPz0) by [Dmitry Petrashko](http://twitter.com/darkdimius). - [Dmitry Petrashko](http://twitter.com/darkdimius) gives a high-level introduction on what was done to make Dotty . - - -- (Typelevel Summit Oslo, May 2016) [Dotty and types: the story so far](https://www.youtube.com/watch?v=YIQjfCKDR5A) by - Guillaume Martres [\[slides\]](http://guillaume.martres.me/talks/typelevel-summit-oslo/). - Guillaume focused on some of the practical improvements to the type system that Dotty makes, like the new type parameter - inference algorithm that is able to reason about the type safety of more situations than scalac. - -- (flatMap(Oslo) 2016) [AutoSpecialization in Dotty](https://vimeo.com/165928176) by [Dmitry Petrashko](http://twitter.com/darkdimius) [\[slides\]](https://d-d.me/talks/flatmap2016/#/). - The Dotty Linker analyses your program and its dependencies to - apply a new specialization scheme. It builds on our experience from Specialization, Miniboxing and the Valhalla Project, - and drastically reduces the size of the emitted bytecode. And, best of all, it's always enabled, happens behind the - scenes without annotations, and results in speedups in excess of 20x. Additionally, it "just works" on Scala collections. - -- (ScalaSphere 2016) [Hacking on Dotty: A live demo](https://www.youtube.com/watch?v=0OOYGeZLHs4) by Guillaume Martres [\[slides\]](http://guillaume.martres.me/talks/dotty-live-demo/). - Guillaume hacks on Dotty: a live demo during which he - creates a simple compiler phase to trace method calls at run-time. - -- (Scala By the Bay 2016) [Dotty: what is it and how it works](https://www.youtube.com/watch?v=wCFbYu7xEJA) by Guillaume - Martres [\[slides\]](http://guillaume.martres.me/talks/dotty-tutorial/#/). Guillaume provides a high-level view of the - compilation-pipeline of Dotty. - -- (ScalaDays 2015, Amsterdam) [Making your Scala applications smaller and faster with the Dotty linker](https://www.youtube.com/watch?v=xCeI1ArdXM4) by Dmitry Petrashko [\[slides\]](https://d-d.me/scaladays2015/#/). - Dmitry introduces the call-graph analysis algorithm - that Dotty implements and the performance benefits we can get in terms of number of methods, bytecode size, JVM code size - and the number of objects allocated in the end. - diff --git a/docs/docs/usage/getting-started.md b/docs/docs/usage/getting-started.md deleted file mode 100644 index 1c43d6e5adbb..000000000000 --- a/docs/docs/usage/getting-started.md +++ /dev/null @@ -1,193 +0,0 @@ ---- -layout: singlepage-overview -title: Getting Started with Scala 3 -languages: ["ja"] ---- - - - -## Try Scala without installing anything - -To start experimenting with Scala 3 right away, use “Scastie” in your browser. -_Scastie_ is an online “playground” where you can experiment with Scala examples to see how things work, with access to all Scala compilers and published libraries. - - - -## Install Scala on your computer - -Installing Scala means installing various command-line tools and build tools. -We recommend using the Scala installer tool "Coursier" that automatically installs all the requirements, but you can still manually install each tool. - - -### Using the Scala Installer (recommended way) - -The Scala installer is a tool named [Coursier](https://get-coursier.io/docs/cli-overview), whose main command is named `cs`. -It ensures that a JVM and standard Scala tools are installed on your system. -Install it on your system with the following instructions. - -
-
-

Follow the instructions to install the cs launcher then run:

-

$ cs install scala3-repl

-

$ cs install scala3-compiler

-
-
- -Along with managing JVMs, `cs setup` also installs useful command line tools: - -- A JDK -- The [sbt](https://www.scala-sbt.org) and [mill](https://com-lihaoyi.github.io/mill/) build tools -- [Ammonite](https://ammonite.io), an enhanced REPL -- [scalafmt](https://scalameta.org/scalafmt), the Scala formatter -- The [Coursier CLI](https://get-coursier.io/docs/cli-overview), to install further Scala-based applications -- (the `scala` and `scalac` command-line tools for Scala 2.13 -- not Scala 3). - -For more information, read the [coursier-cli documentation](https://get-coursier.io/docs/cli-overview). - - -### ... or manually - -You only need two tools to compile, run, test, and package a Scala project: Java 8 or 11, and sbt. -To install these manually: - -1. Download Java from [Oracle Java 8](https://www.oracle.com/java/technologies/javase-jdk8-downloads.html), [Oracle Java 11](https://www.oracle.com/java/technologies/javase-jdk11-downloads.html), or [AdoptOpenJDK 8/11](https://adoptopenjdk.net/). Refer to [JDK Compatibility](https://docs.scala-lang.org/overviews/jdk-compatibility/overview.html) for Scala/Java compatibility detail. -2. Install [sbt](https://www.scala-sbt.org/download.html) - - - -## Create a “Hello, world” project with sbt - -To create a project, you can either use a command-line tool or an IDE. -If you are familiar with the command line, we recommend that approach. - - -### Using the command line - -sbt is a build tool for Scala. -sbt compiles, runs, and tests your Scala code. -(It can also publish libraries and do many other tasks.) - -To create a new Scala project with sbt: - -1. `cd` to an empty folder. -1. Run this command `sbt new scala/scala3.g8`. -This pulls the ['hello-world' template][template-url] from GitHub. -It also creates a _target_ folder, which you can ignore. -1. When prompted, name the application `hello world`. - This will create a project called "hello-world". -1. Let’s take a look at what just got generated: - -``` -hello-world/ - project/ (sbt uses this for its own files) - build.properties - src/main/scala/ (all of your Scala code goes here) - Main.scala (entry point of program) - build.sbt (sbt’s build definition file) -``` -The scala file `Main.scala` in `src/main/scala` is all we need for now. - -More documentation about sbt can be found in the [Scala Book](https://docs.scala-lang.org/scala3/book/scala-tools.html) and in the official sbt [documentation](https://www.scala-sbt.org/1.x/docs/index.html) - - -{% comment %} -### With IntelliJ IDEA - -You can skip the rest of this page and go directly to [Building a Scala Project with IntelliJ and sbt](/getting-started/intellij-track/building-a-scala-project-with-intellij-and-sbt.html) -{% endcomment %} - - -## Open the “Hello, world” project - -Let’s use an IDE to open the project. -The most popular ones are IntelliJ IDEA and VS Code. -They both offer rich IDE features, but you can still use [many other editors.](https://scalameta.org/metals/docs/editors/overview.html) - -### Using IntelliJ IDEA - -1. Download and install [IntelliJ Community Edition](https://www.jetbrains.com/idea/download/) -1. Install the Scala plugin by following [the instructions on how to install IntelliJ plugins](https://www.jetbrains.com/help/idea/managing-plugins.html) -1. Open the _build.sbt_ file, then choose _Open as a project_ - -### Using VS Code with Metals - -1. Download [VS Code](https://code.visualstudio.com/Download) -1. Install the Metals extension from [the Marketplace](https://marketplace.visualstudio.com/items?itemName=scalameta.metals) -1. Next, open the directory containing your _build.sbt_ file. - When prompted to do so, select _Import build_. - ->[Metals](https://scalameta.org/metals) is a “Scala language server” that provides support for writing Scala code in VS Code and other editors like [Atom, Sublime Text, and more](https://scalameta.org/metals/docs/editors/overview.html), using the Language Server Protocol. -> -> Under the hood, Metals communicates with the build tool by using -> the [Build Server Protocol (BSP)](https://build-server-protocol.github.io/). For details on how Metals works, see, [“Write Scala in VS Code, Vim, Emacs, Atom and Sublime Text with Metals”](https://www.scala-lang.org/2019/04/16/metals.html). - - -### View the source code - -View these two files in your IDE: - -- _build.sbt_ -- _src/main/scala/Main.scala_ - -When you run your project in the next step, the configuration in _build.sbt_ will be used to run the code in _src/main/scala/Main.scala_. - - - -## Run the “Hello, world” project - -If you’re comfortable using your IDE, you can run the code in _Main.scala_ from your IDE. - -Otherwise, you can run the application from a terminal with these steps: - -1. `cd` into _hello-world_. -1. Run `sbt`. - This opens up the sbt console. -1. Type `~run`. - The `~` is optional and causes sbt to re-run on every file save, allowing for a fast edit/run/debug cycle. - sbt also generates a `target` directory for its own use, which you can ignore. - -When you’re finished experimenting with this project, press `[Enter]` to interrupt the `run` command. -Then type `exit` or press `[Ctrl][d]` to exit sbt and return to your command line prompt. - - - -## Next steps - -Now that you’ve created a first “Hello, world” example with Scala 3, you’re ready for some next steps. -Consider checking out: - -- [The Scala 3 Book](https://docs.scala-lang.org/scala3/book/introduction.html), which provides a set of short lessons introducing Scala’s main features -- [The migration guide](https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html) helps you to migrate your existing Scala 2 code base to Scala 3. - -When you want to connect with other Scala users, there are several mailing lists and real-time chat rooms available. -Check out our [Scala community page](https://scala-lang.org/community/) for a list of these resources, and for where to reach out for help. - - - - - - - - - - - -[template-url]: https://github.com/scala/scala3.g8 diff --git a/docs/docs/usage/tools-worksheets.md b/docs/docs/usage/tools-worksheets.md deleted file mode 100644 index e503e72f0c23..000000000000 --- a/docs/docs/usage/tools-worksheets.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -title: Worksheets -type: section -description: This section looks at worksheets, an alternative to Scala projects. -num: 71 -previous-page: tools-sbt -next-page: interacting-with-java ---- - -A worksheet is a Scala file that is evaluated on save, and the result of each expression is shown -in a column to the right of your program. Worksheets are like a [REPL session] on steroids, and -enjoy 1st class editor support: completion, hyperlinking, interactive errors-as-you-type, etc. -Worksheets use the extension `.worksheet.sc`. - -In the following, we show how to use worksheets in IntelliJ, and in VS Code (with the Metals extension). - -1. Open a Scala project, or create one. - - To create a project in IntelliJ, select “File” -> “New” -> “Project…”, select “Scala” - in the left column, and click “Next” to set the project name and location. - - To create a project in VS Code, run the command “Metals: New Scala project”, select the - seed `scala/scala3.g8`, set the project location, open it in a new VS Code window, and - import its build. -1. Create a file named `hello.worksheet.sc` in the directory `src/main/scala/`. - - In IntelliJ, right-click on the directory `src/main/scala/`, and select “New”, and - then “File”. - - In VS Code, right-click on the directory `src/main/scala/`, and select “New File”. -1. Paste the following content in the editor: - ~~~ - println("Hello, world!") - - val x = 1 - x + x - ~~~ -1. Evaluate the worksheet. - - In IntelliJ, click on the green arrow at the top of the editor to evaluate the worksheet. - - In VS Code, save the file. - - You should see the result of the evaluation of every line on the right panel (IntelliJ), or - as comments (VS Code). - -![]({{ site.baseurl }}/resources/images/scala3-book/intellij-worksheet.png) - -A worksheet evaluated in IntelliJ. - -![]({{ site.baseurl }}/resources/images/scala3-book/metals-worksheet.png) - -A worksheet evaluated in VS Code (with the Metals extension). - -Note that the worksheet will use the Scala version defined by your project (set by the key `scalaVersion`, -in your file `build.sbt`, typically). - -Also note that worksheets don’t have a [program entry point]. Instead, top-level statements and expressions -are evaluated from top to bottom. - -[REPL session]: {% link _overviews/scala3-book/taste-repl.md %} -[program entry point]: {% link _overviews/scala3-book/methods-main-methods.md %} diff --git a/docs/images/scaladoc/inkuire-1.0.0-M2_js_flatMap.gif b/docs/images/scaladoc/inkuire-1.0.0-M2_js_flatMap.gif new file mode 100644 index 0000000000000000000000000000000000000000..1cc25b5683f757431e308a80fe3851f94034bf0c GIT binary patch literal 352175 zcmeF1`8yQu_y1>~!O+;3EMwmp`&b+Mp0Q?c>^ozrglf!K#+tH3Nn;Hm6++V3cSa$V z>`77)Nm}OndjB2Y&$-SI=ePU1uj~1|u5%veSXx_Pb^S6RE1;i1HNYhRfC&J)v4A;v zAlyO_UQsB&EKE@He<>sl6PAN3Ya#eW5i;5=GFq(vg|G~(xDuN@mR;B3l$Z=kLWxrm z%f-dTt!~02tI98@E`W0pRMZfh_$ef(Dx{=!TGK?>_PmHHR>Z(gG`&+y-wKVNBZ7Ru!{DmW`u0~3tAf?Dc*brWm#m^}54Molw2EeCI{U}J5|v)Wcp+Lz08^p&x( zH?hfg^se61x3V{|K5Jm7YCx_tw0ALd^)t+AHeCFB#v>5t;BK7v#N zw}n@rrG%`do3CYApA{j}`tGoer=P8dpKay1T~M4|)#O>jI z`1!(<$q|WHqvYhGGHynvT#dPw5qp&qceCmunVN{xO3W=x%rCi2y`FUIL2`TimF(+R z=#NPxQfh8N>h&VZ)l5o3aau`x`iwJ{|P4@+ws?o`*^x!+h`*HGR+ ze>YX)ZbS3kq11}XihDz^Y28DWHfB}LtyK@(s>k2of80?&vtG~0XkctSnA>XV=x%!U zqPerD1ufe0Vz4#2p>=Wh5#Hu;tMlWY7mw)!Pu_iNrw_D$Xzx%~e0oN!^V`?1!I5Xr zo;@F(=(9ELo0#sKobH=q^iMGcq9cc9UJl=p8hbf6e)M%>ZeenMar*UJhMV2&+ohN9 z-oIK}o?l*FoSu67_U)3I%2IRVdxG0aWWf53oXsm2KV+tEZGYM>FWI?M{JFb*xAxxG zF3G*=$^E0FU!Pz7J~{dK?+;{Qqnc1QWo55VmTi^-&Pq3f`lwl>?b5Nt<%3M^!^PoToyU zMjus=Tt}N`3tK;~87q`?ZuA~|Tsv_K6EI$G{iJT{4mN&gY3#}UnR_@&+@Muk{cN>W zp@PpiPbK3%zS`!lO?%_~1NSH4@5kF8%s>bO*?Di;n%+DKebpGX)872RBlDz$<9X`Bl&+tQMO%=1IJ|9B9S_pS+OI(y3mfOhHT);YI`B&EaLiAX%OWAO_A$pD(pT~_nE18DPo5yPc3t6Ix z`*4MN9%p1RInfvh;ceXJbmH0kJ^-*N3EMKUt83W09k~_kk?!jf_Mtq%Gb@|lhvR3E zqwi)vhdxia{5B2T9=2UcmGQil1swMHSbbr+OyazV&mjffm3#2$ev@UlQ%ES{Yu9%6PGI#^hrVpZqkL%(lZC+F zA6pI+a~vLi2~58Ja1*xV*A3y1#M~UM_(^$&f=|_ z2D@|MxEFU>Bh^#j_nW?tBU^rpLD@BO$DeR!ru&&}9Da`NSb7|PYUE@O*=mZMGiKA- z^scrQ6I5~?(Z!##F5)P}O6Fsy4aogt`;T^iye3?_g@H^APbw+wJK21zd)`}kO8@YW z*Y)Ys-?|l{{8-33kq{Y2X8 zi#PaV{_In`ntb2Hd&Xbi`q@PJW%Sd1Lq&m6A^XTT;@z_d!{wbn`UeoO=(Zon+%o~u+yYBFNT@)u@VCPUbP#*W?tsXJxJ;ux zPWDSz&L*eyl}&HY<}d8C2EKW0@vF+%q(?0cxTl|~!1^6%sHrSZd2r7h1=J!YlF&D| z?*fYB>7pllnK~^?Gzzd)SQ1N)oK;*r&T$x5j_@4rpBD)+-N+$d+iULO&Ex z$%y0(&j>|8zP7T}xSI0xOCq3$w44Yjb{;)B#NTN(eHhJ{cOI3g6Z$AU9Z!J&RzwKV z`0_QsGxAzHl-*i`tl&q z1TY|2k71HMP7dyIHcGn#q!4bOHbkeoEe)2Wsk{4+&QxnyHA9T;I2GbUc1a={ydc&W zv0zSPEEUl+`!t-qVRe;c<8H4>C0N;O)`cX&^J~N8Of3 zS{Gght6=d1Y}&0LOcSBPMa~-Xn3RsnMYDv{0l25*^FyoKX96|0^|%_Ze>O%YpbRVd zBa7K0qZ&n?bG@m1yofsG!W}!^I%V)p^e;Ea7mnJI1!tyS0o2<+8&()KgbA> zai7nHwE~-CcJ6MC9mfxGFyY9-3JGfyLu)RO7M89Rl4yMH+=OShlpS#Li4#{@Enb?r zprpiNou;*PyZO=~s~Dg2`+K+}N~Q~rm(HEx$3h&9FX9$QCa&T9fm-9Nn|GcRe!?9B zwBoF|#Y?`NR%@ZXnHsJ|+8!fd^~4MfrL{H=ce21V3d$CmR*~dLXQR_#N|7{44#tkf z_}<)t&@mm6Rt@qrzy4U=RxIGcYp%Zak+med=$7i!275#KdFl`tH8Jd8#-Y7{Sz5+N z;xI1s#D^SN8S~N=At(jR;kjL%^Wg{5=?y9!HR>!WfFIz(kbuGj0LY%&kHFB=>qSW{ zXQRUrn1VD7GlDrwD+$#}^n@h;nsB}x^^5d9mKgaujhm#AlfKJzNO;Bfl-#iv zl&vUXR6oe19i8KO-6qa^jN_P5%NyEZpn3L4r%&qM-~0YUcoi3ruWNb>g*Rpor>BBA zS|KWtx3PC%6D*5phuNbMfY2krX_Gxp;nqqd6Z)hnBuW7~vS3rHv0mK~i!W>L>W`Us z?_Ct{y-3fGB6Z_{awZwQK4d^)y|}3vit4-C7L(rlwK7U5)7^XHVqP>Aabl5SeQ8*Q zBQaGdjR;Vw(UCe$pj_F1cLUM720_QtS>{MFp1*&uX#Lu`7VVP@+o_(6*E=w-^z&*1 zaf>h1YYZGY}3Go~_eOULko3_i4E zD6rg=v3#@!6ZaX~SbB2rf^D|@pcSi_F^NkSGPGHm##3RAs1LdW$Tf^y@i&I?;8$64 zjjT}kq`X_)Qs6631}1eR`Jo7RNk?jbVHbd)h5&+Ds86rhUjZoW9T-@xSaIK`b1G>9 z+s-;X-^nVh_S%Y@Jfx36bk89}YbZ(HG4s%;@W`u|6{E$gz0lV6kr{Y`-~>Y6_%?fc zoX*cKXzZ5mI<8=#%=?{s4OEW>lvw|$yeqlnJoCrzt+b(QGAgz9CJ2*Oi1r_y(OatD zSupgBs}?u}?*1h~mpdfKpI(xu(SfI1f$sAT4=#}qqnt!3%isWM#-4%Kh!PLc>#DKp z9z!+$iQ18g`EVe+=tb1kI#w?l*nxzQPhfX4_4!EPxF(Hq!m!V{0XKC}JT$h8m*Ujh zkoanM@LI@&>BN$8pWoE(E9K*>LVKI#axA4BA$Dlc}Y*oWoZ>=MuMgBCc^uG3UGr>{8bw( zfe82Px?^G1qa^mw5Ntv>OWD zNAY7E2c@jW(lVvuL+S$IkMQi9tL)El2sLe#APF&n=2$DxGQZ&7O=ovMK#xzQ;^}ZH**tC6sAU4jaw}UBI_!;{zel)}h~zZ(x~aoRVFI2A^CzV3|{7Z62&D!cVztRW@c`RrrvD`O^4eNg=+W z&``J7rHmh>g=ek-abrpx&>S7foR|-4-vK(zxKjxmMKOgrj$I{C$KvQ;B~htLgvw&C zUviohH#<#b_zgDxZ4FVde(c4I8o!DnJxb34Z&AxirQ(W{YXH%SH*ue!K3Vxn9w;k$ z%{_qr(2?qcSAIHSrL>09D&5;A`<|>cr3;^w3gy+f15jN6m3Z)}-zfFv_26sk9Di;i zX2-E+8FA>q;mNe(bA)t!7*{Df`=XYpej7ReJ*j5hp`Cgw zx&BF7Y!+qkw%W#14)?a^t$dBCO$|TD)7G;VwN~SveHSlOs}^1(=wD07mhsT5tML$R zsx$FlvbE94iJw)P+AdE`pqTbVk{)c)mGNWBxG+ZYXuIjLgbBSuCnxy zn%|yq^P*sRt*mquvS*bg1prz~YHN)}CDU4YFo+CGfO9JhNe9HCp^!&y+8^4!yoG|) zpz#Ffls%~GEua@h%CHq4Pk*S1Xy%%Q`rrXb6l6jhVW)vYDx!Gl@Hjjeyw(AVg{0sB z(QHrSk{>}TANjn4E8zh==>Im$(G(>-Pvf`wd6NeE03oEJv=qv^&lBB3>+Zv(`W81~s7~Fo+bdp2*W(IgC08o(})h z>h0CyhXah=K@H@D<`6&-VlR>enzDtPszZ&WQ4+22IL3cEM<7>wK(SAet8J=E&Q~V@ z=WuWczF*crN~{$TkAYty^_;eaoVP_ukRI(#)NiOke(Mi$>jngoSsh^)ZiUc$Puo4yhE7GGr&cD~XB1Hp^!96ZJ=(?eWIB-A zG@4tEk~NqrP=d=4pRVl;Bw!G!pk8=vKff22I`ORNbFa8gmzA)nAE~JV;Q9LP#L4My z12sk+8&?9UDV{!Qm5f5s;a=6ilmZ|R{pq<@7*P?vp#bK=0aIvw0?)7e>_KlR!Z%%k zNy2hM#8xnH^e^)yPN@}sW2q;vXH;Jq1!X|(3xO#_Qw8syczUajJt~$s;)X+=5t%c+ z(wq7DxibSUK?m@VAlHA->_;@N#Ue(-p%TD_p4|!7=iDj81y(G0GzoD|X|_HaC5MA2 zGvMQ1;8)`SH&n~H*2rYi!+4+9jHRdcQO>;OK&SyCp5PBb4}Q~wKQRTu^x<(d{f|Ab zKG~r{Y@fot=cINY#t|XS!kzLys5|fBDT?!gpPy$L%urfk4r~*7LZT(4CUrDdJh2J! zms1*pctB?xrL#RCBFq6m3CI8J#@d5Inw(}$D0m^hKOvsFG(NS|v%18%!e!1Fh%W%* zm>|%o5G!%2dCsP4eHJll1C~$&SFEy7_Bc5K3%2E54*-)wYS7Y%7o#{hP5QlP>dL=o zD=|@ADvX7V=glATXzTk7_UBxJ#O8nRkepMTKEiA4|2Y5Iukl@7Q+HgOLc!qEO)S1u zYkr`EyD)GICn_IF!GOg8|8=2jQ}`#RZ!C{pQ9^v0sX zg8B{MQ~KZ;zID3Z`d3|1?Ur}WdkdnX$fGat(QJsY-^K&R=IOrGpuDy4W=>y@Eg|u( zXYaXCXpkRnXbOe&{<_)6`e8v=l!dWjauwl*2iEfgdr3{6dz{ee7skuT5M~d*?J{x{ zMHc~X248K;TISDL-d5}b9VN5v*nhkb{gEa6V*+MnG#gogf`#^Sdg2&pPM~eikoGhj zUHMT7x0SK{VTARwnD}Q!M^J4t+taB}cfWqhxGbhbL_90+>M4K?zvm2mj|@g}{W63K z-vCMgK>01Cq_Z2>eYfDaFAK}GH&;KMxb6YYi(bYtnaU*aX`tnwQtRwd=I%$Ds1L^Qb}vyMEky7 zy7v>@{!`R}8};vNnAq!xQ^o7C%~qmZt5=$It^pLjeSE9DnK83VS@{{{3n^i8rZ{lT zbAV(3o=MSdnb#V#9v-j7Hgk(|iP3h1W_Mq5aPiWBe5>0Y&*v|mWHkIXoq3ogpQmr00 zC@ezqW;a&}eHd2w*}+guUcaf}DHoo_(G9Dc()JZ*WlkS#N|b$i(*&Kj>~3pCEf1DC ze>_`Z7{CP(a@odLndga`-*)-rRA+zJC|$^P$EDHr-pSzY`9eA&Od>FsXjSM57D<;lWwA<`lrYX^fvOu=>1>+yB=LUN`Xw%~gb}bkcCwQE95`OA ze15px;~;qYuHiKmtnp#!%Ub(;7I!^=gfBGvyvPvoI*NST&Wu{gXZO?@#`9efQP-fP z=SZYPdqk$7Kn;%)f>Y$wGWji^umrmw77g3nHZHhh&zxAGt)xdb2fUtsuYdeqPG{jR zXdTRMlmq2>d-pu^>c78#nQ#n!oG96f1D`U(7(@93QCdKqiB;5qQWd^ZSN&wQnN`{I z!vl)wTRht6Ppg~&{Uzc9Hod^3mXpo_P#fg5O?f2s-6T?m2P(Sx$WrVYMBPd}v%KC| z^17M2we+pXg3+AeWv3>u z^r{BJg&26I`Vlo_ZTNHZiNhJ@QlYgmT)GW!$`46k-aplk4J`I5*f-~M*v947aKSv% z`2!O@(y!a7-LAUfMFs}*>S@Z=Bd}A0j`kE2k@h)fXCJLv*8Wg4zVq5Y0y)^YpxW+! znbIALw>iwUJ%VnTFSv(jO&oZH-LLKNj1UXd_KJG?;ix0x1ysj7c0~HA_xo;h9iI!Y zw4VB0T1nUOy*%Xe)HnH?NP_Q`pC6u{zs5A=Kc5Ph>BNyvSz!Ir`Gb#XWU&nF`n*tG zr+<#>aH)Hi&X&M>?irYF;0;Syb3ma(%dNoTbHQCfw_Kf+*`xQe;J3JaA6SSjXbVV- zrVLhsgDNxmz64cYx6ljAaeifTFW%w}^qw(sIg{D$a~SraApYLT=l^FN|y z<0|gNjyUM23Zx)L^y5?iZuP{^oS9K=N3G9V-istx5QMG>RR-|4Kj};72sv_mcKhj* zPwA%uLUp2UTsd4bjbGb`K2O}ZZYe4|uk9{%=Ow>~F>$VG@%{~#NY%Wg&$evhdFAt> zMkyByWnZKm%v>tf(l}g`$-AN{ubk^Mm=$u*+3A|s)sru>c~P@fG3m#UQRPEk1_{3F z74C^iZ~qh^G&=wd>nEKGs1avBDL8#3GQs}7D!g)LRq%#YQpM2NTw z=C4L%8j(vh>?eWzl+^(v7$@0cZzhU+kHT?z^u;U*9FeytxMkBhXwtyQa!B(ZaC!pr zKSqXDu^6kSxaILi(u6cmLv_Dq8mf{Vb8A@oFdd;VnT|(Uj%fkH9}ucK3yvxAg8`yH ztd#YS9OIKAfoSL(*)x3KBPeEp61;+FQ*EbEgubz0D=F37?d46Ugg_bHi>bViQgJ!DN%-bu%0t{E`*9sW z(WTO-i8PX2(Hhz$F-Y+|i4)oC2Z1vaQw5aJH#j5FlJ7OG5R0pT+`#xdxVHfAK^jcW zOdJBu0tlqxQSfq-vUeysQHh?xYc_#qB~T16=`wEpdP)14#DBUj>&97iV<2PG1ouV) zqLoVkNw#i36mptkAvoXR;skM2@j5-B7M63X-9H0_OvyE&A&RJe!Ck?b%c5vVrzXPa z$CyL0D1Zi%4#m4(#8)*cR$>Wqr-hS95VN*>GX|y(Wu8+JXQf!R+7;aF$M2t2IlL!$ z*_e-`>J?@8ph5IkgG+k1n;qYL^IMy3w!v5UEGZI;!Ci#8q5A*0FPm!X7Etdp0AAEr zOu$(Aor-YQjzqJDul6(bp%bt~R%2vPC|Qn;i;OoaVFS7T$1PXS#qgQ6HAQ}4_fXW$0R*UD&UMMVHdgpIK7;;EMr#Lvd($mLca%6 zCqzU4PWi~?n*um3i)L{o?1aB5SS7nSKVEb(C3lfrh27tvNBhkBmz`J6{ztLribR)&nmFI^B9Zci-Ydg{MV+G z7DdY^b|E4TX3y7zLyWl?VTaK;_MQ2rTMkJi^&D9ckT+896d}?ksg&*Y7P*Zrj!fVW zgyb3G_z=o4F4K2tE;^1o>GL+v!_Fa*BUP9Z0fh3P7%hg;ac1x?%Y&xhc=+QtrM_f&Kk<^xdV|7saBg6rJ~< z95Rz$d0YX!P!VS{7y<@qfMOqL>j77^V}{hee*U3;R5RcfHN^fhO-4BI0h~$_D6oMl z&34|bjr|39ViO;doSBpvpUxhm}Yo&D*KrbILnCidF9uU-#hN-st6!Ni4NsRW?p95 z2Oi-JWJ42o1UV$hY zR5Bu#UHnghCP8Qc(4MhmKy+8p^>?*`oJi%6cLa_ zk%{wH))MG@d2&BePy6joYhO+YDiowv+Qv92s3-&|5pZ#yXEyXmoOF=ZD4CrGx)Ra+ z_wx${2tRPJUun)H6)fYYE)$?oHa$#VSk#b5%}@ho$ZK#&v@qMZ z0K!TG$aZE}lFU7thWs^$%_oNfT`aB`oBKhsaitl42E$=B!!-Bdh(U|^uwfbk5>j9R zs;2}2GJOj`G%VS-6c&p&7pNb;SThirHj>y@5+y}Kcf!;QhOzZ95jm1F3ND5wMI3`b z^?+yu=#tqeDS%YvK3ZEal9^`ZZ)_g72fM%nWu7V+4(g=PBJ>m2V$ zm|)_DeA56tosg)}vAa!_FoLE0u_Xuri3Ma5OJO>46aA3KwJs24>Ucxi*wci`kwc`5 z%TPQW<|;RKR|=p{gvFpOL3_ZEL~9rh9D|vB*_K`F4bdY^4yR2nB-oEzwJVmwasx@Y zMChx*sRkNA*WG?0WoiX-mRXM1G9+e%6El1#r#3a)R|BWF%2__7O?xCvf2uiKOr8Eb zH@Gu5{bdrddpK>jIlZ?z{Y`4-63@&*`Sf=e2W7LFqrmAOX)}P7TOiuZN!!ft!I?jE zGk-T{{vFORAq)U711QY^X)(a&42UZO8pMEIV8GKEh++myErT_Pp_n^^oHzKn$#^}- zIF;AU!8ex<>it?uf~bi9)t#sF6m$?a0Vz|8JGgtgw=Hdgv|+EjHzeOizliPo7Ggklw_ zhcWvNUf-Ha$Dv8?0uwY;Mm5r1N!T4^H9;|VPdE3#-ex_umvJtUjK-zKCxSr7q_SE- z$Rdap1Hbr(6y7@b0y)_y1<)bFE*_Gw#D#(>gFzR&Lc=#j>7Kk**{4cfVz<*NQUC#3 zdRQsUB+()yG2OBgVt72s5VogL!668E2-U5YchS&lYFTRGVprOj0X&8V)x>2P(MXil zch5h-_%JM*1wcw7B&0PLS)XA^$T~%(Ocwxs5O7x_OMg^WP-$A(D$F#LIT7kkN0`)S5YeC#E1!~jN<1OU2;p72>ci|a%u?Ql5?3>v zEQJ&B9th%3fcZo%$e>= z2n%%PSOVC7E6~+FgMx$T7y-C~f$o6J@KT84KeC-6{4AC<@D~(<%Jji5g9X6Boq-0S z>k-r?+pEiJ^)S9|XephLw={rXs~0y0!H$8;qo6kS z8)#}^bZMIMTJTzP5CQH& zmKNl_5Y(YX6)6>q*@kdnNkR2#I691(QL++LPcdP@vQ-c%3m<(~KavT-`O6`cV~{`b zgAUIu6x=!41}Y6fJ{NS1rBsCtNx+$NX^eb)S5)g2Z~hnX$jbpM*BY&9Z@MFe+* z<}Pdpe@)9?N*9$268s7+Qb8D^GRf31*Q+ZAGLZuoyUKjfs^$+~DhRHtX>$u<3q}A} zVn**>1bh9i=kRXDzc8lw^hTA@PK^5-#YvcRS@zOA*_2DdRPRPZ-&z=)^RU&>&MQ0DCEsuO8q@ zgk1_w9a5&AbmQ@ea&j0Z5-#36N!hi@*0Ik3i045R`7o8DI=0w2^rZ5dTt1S)%~}@_7s#$iw}K&>eN1`>VD?M z3?C}^^etd)XAB<=Dxd<5JO=R)DWsNwXbeIJ4L2YFwbi}xb`^Cy$insjft^((K4e&$}Da0?7*QB)b$4qi3NO=To z_VLr@hd-0g0PH^|IKUGHms1^8FDT6*IO@SM#NFJ|#E$mFlHtVUYu@?a4js+_%sDPQ z>0A(B7~1{nXgN&HVv={-_sQGf*u?WcjK0aMApEV;4`7*t(NThYaFab*jLuS+`(8XT zG&1!4LVlub^slf^2#eUs?bjEobWR8#y+P-rBU|^w>5yDvZ0=qx;aaG*9QDIj2%zOR z8Apk)PgM?vJ^A^)=~BqUnG<1 zf3w`bhU3y8#P!Dym;3MkrF5q3qmn3cC&=yOj^X6x_VriS!SReO@+hH02l4b;sK5J4 zk;>-IJZZ%e{Diha!9a*13X$~RWHe~?dQj~4zbsNDgZ~c@j)<4x5|&G(O?Q!>+X&7{ zw$QL95OxWJ0>B+9irI9O?%rrwpXx`ffI%rka+EA#T_WXVQ{Lqw!!gK-eMA5updLic zumW;lI5k>mDQ?>P-c6fRooVugbyGKWFC7)dp0zQiLDRW>c77->w)&6URE{`ON^J{& z{W$9Lk@8Y!+{c&A5kFOydy;;B|MHpt+Z#F=&MlK7zvRT!`Is-q=eIXH56;#QDEI!g zWaoFi$jtz^UEXRWR&*Qtb7<9);xs+BN^H6PWbu^~pRmSDnxYRp@<~z3bgc2HdzYXd z#@c&#adABq`!QHv*5CF{wc4WXoRir+2maizXEgChIHTP5Ym-pjP1N+f{AkuuD()j! z!gpTGrXyI?oAn-w#^F-B|gcujJevr9)DLJx^a#-($QYppEoJA%1uCp%uX<9dqCnaagBSe~ZX>AP^m$J0Sj4>uHK z3H_3C?^=b6A9|WpSY`aPZ1Fx)tlV_%oI0NwoAR^wZg}CIuUPNcVoZQoj*Yp_d);~Y zwD&+mD~UMWEQGj2`f0z2ei9gEB94#`$*3tNuurn{bglo4b;YTj`nL>5V z9*@bp4YognUb*7`7z(t}Y4a7YF@9s){wGdLNzdlV6jrge(D+gjCDA?kXLHpA=FIB` z8?6q_jeS;%kxX3f76SO)KIjhfS{w8w2*cOo@K~u#pjmAR$L{VjD ze%U-q3MmMSge4~G(^ZmU{~P(xK0Mww;w}5oah%O%4v6hPYQMo^7%kbx<23L$nu8T3 z1zfipKWse5)o{V&n#~&o7ZSv#QaosjU9*6mLZwxZnx*``UJVR7!{Y^=M=o~ICHZYyVK8w3jX_AMWTO6d!2p56`l~8@| zWoUs`$9|r4mL%N6OjrLV=6Zdyl+=((x3$ybnxe321ppq`59--UlG*H}uz26BIwR4?o*OSN+T)no z%(CJ8LH|4tn*>WVtq)?gJ@{wQvMp?vjF8T;>m%z<`hT@3n-tDQjykdkwytveub)q) zS)mcAIokJq7Yf#sLGg!z2C;B#j~ct#wp1W|G2{$0D}xmyf#BJb#x$GeqVe0M@I4DO zm9GVU2pm5Nq}b%r^++)AO)U#TTR+ktkH~OCkF~NBA|B0MlUaac*gg)UZP` zLZ;I+OK$@ufg`ZJO{A(^&Uyu2T$74LDfzK~cFryjZ2Ki{sk+n(#ZjxVIZ?X-wh)&} z)~{05%A-yPqrk|+bv7%EneI)0a@cAgS{Tb3Fkr)egzPi^?jU+Ho^7kx(;b}uX7_>`E_@+ zti*QbD`v0y32v@h$ba8bHpG|;KVLMCO0dv8>gMka8>dTm8gm5m@O!@^#-I`YAip#U zAM<&fAB>R7?oX89uAQ8CkxRAke4?2cy9E9#vH$csD&syED*^amkdDY$;7l{- zh$5I=6u6=|sL9w6OU@=49H|wgOC$M8aWJihd|Po`!08Pv=BCk$t!(Mch;=`VpWQ@K)e=dX&wYo??Z>@Afs$q>iHX%*EsinXMiKSt;MLCoJ?b7*O%nr=Im>VP%gvHl;uOm4k~`{S_#&Jgo}rn_;gYd zcaX-rH_%k=W(oOD-ZzT?WNytb+S5V9=^6ktLeXj#SN^tEe}3!5a}m z4M=p&)mwPd@}oKay^;x2Z*icav8C|&ZtxlXx35}`+Mm4t=zmRrX@lcd$E)XGFTT)U zK4|&*{F%?!tIXuZUn<9a+`W4lXAIWGSdND@{(a24X0R!#`fJSD_egP?$BjV6NE39(SM<9qenVoVmAaqf)MAyB8t znQ)lumc|MYLc7ya$v4tp6^%n-um1fw-+=1-%bNyLM>k+?=B!h7CLIW)VlUIP!EtB* zvJAsXUdDs8@N)FA;fi8CR009^UNTl~6GMG{_uJTUE07MiUt;4MlgO(l4AW=yfecsVjOG#xwwSL5+-Cdk_)K15K9q>6XR%vN^YBY(nyMUYhe^lBy>@86D_Id@5wL` z?nx6x;iR?SNiQ4APiF8aRVk(oXbOOSyy?^QrYI0`s9t|>r1*R3HQ+XgTielN+eFr^ zT;+B;Up^~Wxv78!S6OK#)L*Ef-cNNpTRCo8xXu^D5zxS>@<5T%NyA#?^B;GivYTjd zBoG@31OkM`Q8*ZOKyDeRRs+?&Evd%^P$p7DjsZ|S6Q@vXBY5H(C48^+zO7jSAM-20AL4ia`3c z5-EyiLW;BVkd%1!b8?} zubH}AYa1POPQg4i3#^SM^Mu2>P+(mpFekt(YAaC7EmtNdKjk&H8+5W ze**CwK^{VU5T07fl~n;;CBCHc7nMo5oXYBURAWpfDN+YCw^M~+sfr}9j$OY&Uya?% z8vENa;f*rte75IW5Gj7_MNL6ozEY0_Op(#w0|jl%>&qP@Ji7q--2v zLXv87Wm)!;9=HQP9Sk!L(LR+|M!DR_4;c1G?( zPA7uV1v8pfKnN9*uH+_PN`i%s{I~tVrWiwojkVe`qfiv_&OTg1zxp8#N-b|L28+_@ zyjZYq?x^xjiozkTBIPegTClJ_L5I@1E}fE34uo zneY}FnC>c&%?hZIHZN9ef;uE+jh_vf3$Kd~Pp5+A=153^{_`9YPOT)YiwS$do!x|; z`y6SuSxkk7+l@~PoFRX11PCMTy?35=WEvisphj`xQ=AJeKKrj^87(IlLjx3_+&jYlvAJyBugz=+yhCh{quIp|a2c=3? z3z4zdVM&)S^XjGx(O(k$(xX-%^uC1X?A?q)nVeRsA5d?s{(81wrAZt$)C$>vJCStS zMut!1X{-v*OB%7|;f*cf55D5%i2&Ba)ZN6-&D|qfEw%v?bMH))(g%&-@=fWsM&-vb z132EM{&#p^M5d?|wO|M)H$*>)6tsM*Qc<>(2R222+Ufsf6Xxkc*QL`%l)zr30rkli zjcq__uqbplRicyRc}SAj1wv~+Z772WdU#$L5IS7|s4GM2OJy-w3yS-Y<5Di#s zj6_vZo^TQ4+k~}iKZypK$Z{d1SsX$nLI=#;ZIcsV%(v`SB$KNid735t>7q0EwixTQ z$=~G3;Kkv)fw=y?2)G!eYA%hVVGVqdoNzd*Uhoj7X+LCx84k}HR^RI?XQIY2ejx=! zjJN}>Da{gAvkbe90tB%r4bD^wnaS=-6rsQy_;0$C&NMsIw{)VzY=#g& z=&QX_HOmT{9A|E8@n2VqI> zIZ3lslc>`XRvOm~vRhynPHuL!(;5(z+32dji$MbrYGD!2Z;wkSk;!^n10lZ+SPni zPI$&_h)^V9v|#dFd%ne5}+Xy`b6@9BQ-a}?0%ZGJ{9eh z&nEH%DD}f>!dKRrq~Q$$Vn`Yg6P%4PswUc#-tMgd@ENEUuZQ~1T=02ia{g)D*SC@q z7yxt?2sM*M;=_ak!<03al_UDTYsaXbd1&!t1}?ztSFr$p58DjobVe|m2sVnkbKMPk|ARyHI&I-omfx@BiOlvN5)?(J^JCLAu+G?wFL6 z15rXnN(oUn7%;k1z>xwfqN0K#ju7dP5CMISkP;CT5iEYZzn|aVaBk0Yp67bp@7HNP z1Onq&k75$!HMHdJKyyFO=FT;F7_{YTYn^zZ24n#gqZ8Db;=mr7I^D#Y%aKBv)#Xt3MN*Zh&r*fYu-!9OI;jCIo33xz${x|Y9x z4#-2_%fB_2eZSbZ-1eQw9e(Q9_r4JWF(;nHabRGji?c<*d=|N8?8?$;A{p>aG7{Xt z&3tU?@cl$X5gj?6Z8q;{73Z)Y_uO!2A2=C{T8OpMc@DX*apMIVVQ6*Jq$x>Ad_1Qqk^1nrT4=XmU|w2Hze`Zwi{HOI5+{zvhH5`L)ih6ivz$5AKWP)x zjdf-T&f8Xt7F4~88`96aQj<}*eRd=jTy!z+&CNJa>tugGf!$y+$>6V+>N8T@G=)I& z^$iSt2*AP<)YnV{0Dn!SSk6xQX0&U^Sh;sn5+wVGL$Td2ZanjyigONXeay+L3dO!3 z{Nr9Qb-LEYs%OHWl4$tySr+BZf4BHOpsM39;>QQauG@EEWzwUGKi1gp&$p@ zYB*mMKY!xaMKiZca!?H`Ud=GYI7YsOS&~&{zV*XN&(nWEF2r7&eTP#zZD0Q--nyP7 zs2TGZpk17BfhR!}lgN;0Ct-{X$6uVd|5st^tzzPzzPq_;GuN+Jf<`_YjKU_Ae!NxI z^V6c!SL9RvzpNJ0Z2iDvrS6 zj#J0(c(es)$xGH#v*)T67sIvM$-{HC;H)y;{P4^bT9Imi^cRhMTdJ*ca^7ZsL_I+Gm&JK zFhX7|BrIH`z!bySPj+jrNJSBOWni&HRv1R zPbzL8f@MQe^@87I^n{srBwZZb0PxZ|lLdqxPJTqGJa4`-<@@t z@%?gfa^`G~o$LE^C6}g88>M8p&T3yNpPs!?JU zW#d~JFB0fv=C0A>^sX}aT}DL7)&DZI|GTMs-IYz_JXD%tC)|d*FWBvP&nzS#^CJvs z5}IZfb-M5K#v7Mm@08k@I=Vyb8?nhHL|IH>u|;n1{$h@ek?yCop!2*7x57qFua@7s z|95D!uibG)*oWN-CkO8z&#f+hxbo61%X{yA(1VvN z@4`mQFU-Y!{qXZY+JDYJ7g9#sLg8EA_p#Sj4HWIs@`nu^W!|zC6a0P(;U7;WV;WW_ zeDvOL#uCKLB;2i1TKzl>vqh#3j9PtZ!^j&|Em8F@)OkDa40%Sd5m_dILAU)^ub|VgbxE3jMeR0h>CKD9``L-0 z6FBi6EaSwauSit=1n7e^?Hp!_%d&OoU~w7Y>z}3g-D&`?3pLt7sgg(byK1F789$yl zIDhT#g&yS6f|_l~I33vc-JjCvY%o@gO1uS#2Bh1{r{)@iRWG)fX)lb~ozZzCB%hb3 zW#6oEd!w8GAeZELsX5`?fjAr}CnqWWDa*a=Fpt-;xNr7Jc5Z=z>jKLOo}B$4#w?Ea zC8dTp)Br}Ft>*sOUevRFNglWyEnXW*Fbm>*lv*Ll&w~ys*Ry+_b12~i@RhT%#DX%* z^YaMgl6-eP$+J(Yr0&4qW4zQZ`=+%!pE$#5U=xyeD^t8ooA|Kg*rqY=;~K=?D3tRO z6)eC{w!snrjG(o;*f+Xj+J9icPXl4+oLrR0_jOJV1u*IWE7}SokrCZWE=@6ZU~bxUmA1HSP)SgGs{P> zWphV&*EalF3vk9hB8GxN0>TNphkma?;ei~eE{p|=A1GAw z&{#>jUw(*Pj+Wrh+)U8*noT}2wgFh!wi9_LG$jF86Uow90;)NtbnP0e>wgI{xk{a$ zT7G~|9OLlg#v|KY12Zn1yQ9AzSTIikV+F4ydQJFwCh)uB*6$8|AUNNr7Ujgq)DyqsMZ0cI$F3OuPMUceF`uO7QFoy6`G_OB<&v5umU zOaSi)<{Qv7=j;f>1SdGPY61T>eTu^zR|_}hw)ZH}p)PUp>wqp@b42gtaTe)gE?Lj@cgz(qz3W!st{FwNCbN618*$mE#8G@Hz45B~8k zg?est49coxkc)}n4`;(n>c|EC9D|QwtW6(McxDhD2(swphZK*eN%T=MuMDVFhc7Nz z{f-qbOQIt6<}mhryv47Yb~4^y9Q=_D<_&5((j`l;lj9{0?zW_J()QSoC^J+4zWmyM%0bO^d*K?8SMpf|&cKkJL;Qb$LExo(kqbhAhL zr}?UQr?y9&LwP=d#hgTqf3b9p;!#IKlnvd^GcrO=xEM_cYD0Ip;w*o%zm_SE&R(8# zc@kScXZjgdoRoxn8}_8-AAq0DAgNBR}aOz)|wbP^2Z`)M`8HNY_8OTzO zG=n&fif`7dNjkWWRDS#R+01@1GrWqgc=UkDjkSJ2u>UGya1Q$Tm7o zvN)eeoK#U|q6Hwq;h+cHFZ#nY@R$MGxk6ywtpB5Vm1nX5(0kLP6fCMQ8Pv5vErVlQ z7qO|9y9`u8xUs0v!tQLhaG9@&5?%S;Iv{_I ztL}340xpFcA2b60;Nk^ls%U6-h8h*OH`26UB}lQhMaqHH;h@97N}Lw~ohmP5P(vuA ziJCg`wE-EJFlLQ{%u{6A#@E$CiP?7W`|yE7)*1;-RYFtlc8m+VO3A#nlM~v0^hfb= zX7@kVAP!IEwceRfFg|#`bG%#i=5o$)3l($rFrgQlyocnG$ihL^pa;eWwh)kxKjD=s z&WzQjQ~7N})w)AfY)M5V0VDV-htF>Onl%s3{*hgw%G_q6$bGEnyU!%8K2(Z2zD7;DIv!s~!v^ES1*E_j--=cs zpAO)(5Jdz;18h=-Fi^h0PVO%}9>?$S!9ztrDsqQLEX-A3k>&-Qd{2xl6YbS0+(^Sl z#OFD83QjoiYoS0479c2rk#y-Ahk`kVgt!)}9!un*`-+?gSL-!@E3-g+3l>pG&ATCm zDFfmH7X=LSlx-6Q`W6Kf<%A-tc>P$<`WMf-> zg~f@YHen*JDl-4nRA7%)2C+|i7Stzl%tfj&tw7N--)Z)a&+$h}@+8Q6f7y4#1d(kq z86FWZ3C9EALx02Zkc*om)ElAVg7)IW7!_!q3SpGsNY&*gO00%0>8WwZt(o%Ri3cE1 zFOhG60QhghuBThKgiFp;L&i8lps-L=L zP3Upa5kl{~N-LCs#*_iA4JY;TM_`M^v$Lj%fl9RT3g4-RDX%|r3iRmHTSfmO$lZ3byL^_DxWvcj_O2F9BguoF(EPL$Usec<9 za$6b>Kb=WS4?taNa)-SUwwVdIp;WubTyym%r9~!gK1e-D4W9mlun}Pg;1N+(QSGbL zpw|;ze*p9dr#Q{c6x0rFsdFEBQ|FtiQ=lL+%?T`g5vet7F6!AEFEBC8QNlJ$R0#p4cluqUiT1J}9aK?`o*1v1vc}F4Tovdz0gfjk zdPwT>ESw4ruCa9aG(NO)R9dByBbdnFRe9biM<^aJ+e6~i+e7>+c6Du@f9{A zf;Ct^b^QExAP{2#$LbWV17eNR#6DBFPDb+?_p90SDFj5(H-civ?bNnGkzl@Y<7iga-)&*_7Gs0`=Bs2kr0l^QyWIH&~Et zif}4J;z@k`g(~A5HK4+N>|-~RuXwNqlTQVGGpal6!0r5ccXW8%bn}9N}UV5g60bc%5czIOz z6}&YPstxSAFUVj)wuq@l+L4-Pui@Du+xaCQ_Zi^IL3ft$@x8AYD2HW@gZtOE8n%7l z0{ZD|;p6Wy?F3wA79fy-KKh}9vxFC!wwfCUjHe=fZ2O)9fP!$IG7TU};@dLCbx;Hw zeFYt<03m=p$9EjDGU#-DXfH*ui*T|6qb8Z4hQ=F9L;jW}8_t7`4hQxCO{|7?n!rW_ z0k0_fdg|u!D+8<$6~vN?5ctH%s(DhiPD>YN{`0}39gSehM_cCH4QCmqskK3%R&cfI zqb{Rulau>?a;2ar24D@-YCr)%W=NuRrw0TPr$VFRCi*?ye{QmMLuiL^1N zlykgPZr3UKS=st}>%gwE2*|zHq zNEBjdVf-oqaWR(}R~;Jl9pmp@#1M`)LcV`Nk;k5w@R~1ImmiN3 zT7LQqZvh;vNjw@Qn5`c0$U$klRl!FKNGzj<#Xpj#r1Ar<8<9_FJ8?mYObbFR$z*)VOvtCi&fpNo+ z&HZFgk6!uXNUs!Z5-sAS2yaq5zUcR-{K2Jrb@E^DALMgT0Tw2Tv?hu^O?%OK&1*1$ zDf0HuV5iqme>;o=I1GC|>SQ?Oa(!yb+=;>xrTcO{-Q|s>0RsE_bbq#pz3g)-5t3yW ziv6_*dA;UjarSg_!ioGwGytB>dssh@iThiqer%AFI9Se&oBhe(j+>m59^xl)jr^II zDx2zmIY0b&KHP;>Eoon^QC-5b$(1N@AoE1H3Csv5NKeV zpvtEGw-2Iw*JriMMd3s~gM*KW3uA3B=YCSKYsC3C$3EzGEE)b=sy=s%PFQrJh{Q7& zKO}*ciA&nYm%aae@-SNj<^gM&{VaD58v#hx+c!Hrs+ zeSCjEll5Qb;jf1$KNQ^j?Rh-(sXFPi+wlx#{R88($CUHY%wG?5f4_hA_g&KO1ufdU23=W&Oe>UBdU8W(2UQ`GN_lp9?8)f1x@*mrC-6IV}NFG~Rr zO7m+F>?hFzVHA>V^e3-!MH`aKQflulLZ$y;sbQMd{n;lM=bm5Z(pKue9r=0oWt#Sb zk1ylS3=|B)=hWQXdK51OJ8~$7EndB(3a`v>J!gp~{vW@+sekPsQm+&VPdDGUT$t;~(0>*(_u$&^e<*|fj~{x{L{DZKw0-+Dl!&;AHhjLjI(*mj zRi@#Ky)W~2_J?Sr_UPLm25+6rGJ5&zM`etN$I9I4vYp+}HUU{DU;X?0=l9nrZZTVO zepON2-Z2K{@;}8sN&?ylenR zDd!4j3oHlK#4&6RZCxWj056+`fg5O7Ge2@uG!Wef)j zuc@4?T>3P_Q>7l%A6T7fglGux;;^Q|R+&UViQKu+Om4Y#N4r}i_e{BJ3;h~-z~#Sm z#S|YDQv&a?U79Vp6@D~ZKsC$;EQ3tUq` zFxDOo>XMp04%cPa@Cf?7MI(#O~`I`i_Uh%pjce4{G0NiTbR z<&}JahzgP%m{-j^8~)qub{PD7=*Ua6d#|5=*%}BNGv>C73_mVv13->2%m9!qXRy7p z)i18*m%VCCglgj&VdyCb$KsI2bKKpC_xB23z>l2-dq>WNyh1&zIX`L_<;~akP-`yi z>u}V6H+1AbszzxX+m@wt^qptX@(6b6K_sZ%`n8`NV;eWw86;lT0D4QpN)3M+{M6=>0 zn>F$%5K=ZPL)9`=gujJ>R;}*@8|)}&wVGq(@jN^NHOVI>xezXW#)5B8B>B@vkjY69 zu|p7+hLFrqO7D|Zj5in581m!GsyA1zkVrg^trik?=_PUmBweXb((&4%(TG$`QoabO zmxT=X>c+VB6Qx=SM_6qIAfoa{AiaePP3aY_U8~~ISwLN`iO+(>&}DxCx^()8f)?aO zBA*00wB8s3jxm*as)7m=`jp?`^@-Hcj0`)XeC`I+6ND10Y8;dAg;1Z`h9mq^bTzMc z%?goc3}!NrjDI(@qV+=P|HvmxT%s>5Gx~X_TKbSb7)G`X9rNQMNm_z(h{*7xAQQ~- zwHkdbJ>DQsczpAdazYTFjUPD=EZnV070$Hwr}DB}%?WVvaa-4wL-0q&sxF^wLWCtP z?|(E?Z=efIpTJ3f8Y1e&K%9M+ux{)A+Zu zKspbRXbk=7)7M{!S8a%adSGtI&RN?hl6{-v-IF3P~@zsr|(IWkX zk2Gz9Udj;K_Wr*$*Z-@fn=fxf-C^HfgL;9A0({mqx8a+jSVu2A& zY-Bjz@&92|3J{H|*{R^$PO`fYw}guTr%4%wLB1V@HUC8+SJ~2BO}>7Ji=8;@9`&1l zPfUpl|9B;`uaxvE6fM7ChCmG zo!JK=<}s55hZmEUdr7$^T^T2cOw1G}l;e3Ml{;DwY`CvMau3bC*623?UI%OO9Ff>v z5?FzmD39dvh;P^FB^Rp(nq33DRZHwAh4{%eUjK6O#mvCGktS)8m^paf6-Q1?^nfXy z6;XdJ{DP6d<5W!jA^&qx*n!on-!%PyXxUivV(jGi%D9=5$O7Q7zqE2lO85fEFf3R{J z-tATP48o~T;-R9fFm(88^pHdy34<*=TVc>-dZNu}IJnMv^E&1YcaiV@{X2#Da`^L* z@5Pbv`Bm{VjJU4fx){?y398uG0FaTBx*8Ae8iD*FLQamhDnoBO$-t+=UVgL5eH`yt z^a~hr6JYjV?)Yk}-l^RY&MMepllCzKk_vF&T-)h=f77!iyU@(--pY(eudanG{1q}< ztq^_j<}Wew^00K$ll|q%-xacFEH0fALjfnNv;`fqdry9pgJI&1{ecCEu%d27Vg{K} z{3?g%{NHiKx*?+S$siI2m>eAQEb4j`fM-8udO0SGbw$qXrf8(aXkyHi%&ANZOnGGZ z6pPcIM)jvg#cE^XehLi|k!@E1rwL$YGZGUW-*Xiz-xt3~q;btMq-Fu zpV)}7W_M_(rMm@En21)xyTaJWc~;Uq-W@CJksw6mq%Z^-p$NB>%;F?-SQa5V##XnuUof6h6=F$t?wSMoWGR7|d1Tdv}JlPPMVJULS_(z|wo zZk8hGK}JcRi$Ug`OnVA7e-<9U76%0)t_!7&1|}62Clyc+qd93A;g-o)-BHo?$)WBT zuLg`P>juOrXC@l3jDdgYLbTtV z(0`Jtin~`!65)oSksJ$!p+SWZr-EkLq{pq{OVOFI?2>lbq>k3W&ep-*(6Jz%OmJ0bCVNKbIBZ8R~DW$L1GumYHR~V%*NBBGy zC4Ck1(fOQ{aF%y+(Qa!|fLq+Z>MZUUNEQnAx2JIOw9CpPNFX6X+ybI4B!gWeV%v-!2r+}0K}pBZ74P`LnlumTin|j11UWX zD`j%c-jsC5Si>##J2`ip(b9FY=KT>KZ@p#seQZx#M9G1+_fr1rK}G8@mnr2g$pv5Q z3%uRXkCQQHbdw96k~x`IAtYc3Eb6)t%&-*0$wEyCLIfBYYO+Pbr;DbX!K>TQK}$5q zxAv&<`N#bbB&45^9S#nSrJ+*APwXE5yUWAB# zOUHcFpgz@hb8oEm+Nk}LoCV%FEQbaboFVQ52A=BSH-ToM`4UWr2KU>%ln%B0<6$ z49KoES3kVQH|6poo>R^7!bhUtbvO{s^{`(Ew&(~uc#fRdgY)!)ELcbvx7uHFMLs|Q zKi_+h9Y!=8c1yf$XX$o`_q_1Ab|Y zfWj_ZL$|n==@qixR2Wt?*Y{+3rs4KM!yT)74BMN{Mom!RTJE(ksUYDo7(2TW419d` z#N&wma3b}OGCi3n(r)dv zWLy4)Hjd86UZiKL`uVVCE;hj8OKI4l+#^Z-OKJyZY8bS6Ag2FC`^T~NQ|HjTF5txN ztAlN2mKb-_2Hvu5gggzd1AZW*r~HxvkNtENcy!1+qYFQs3{ydsV&VTxY!~rJazS;# z%wdsmDCay8Jw)_I@F$ZHK$BR2ezOq!$f?Fmh5EAK_gFAhjzJ=Nb{jst8^y_ot_9H2 zEgxU+cP+{hzD2VCRRV0LqIy`IzwTP*l7tI=U+t&y;dkNuNyHW=thff@blP!(S});+ zl0wo#`mO3AEV4`M@WCsfE#~AJD#HCKvox(}j8lvP($9YO?0q1EA~_LyC1S9v)c2HT zbC5I( zh0QMYYk&u_fdBe|#Vpi<ydp@U?OdWjW8f&tEV=zzt$OBA4+@*w|o8urSLD(`SmF$261Hjn6uw zH+94fXdUvMaQOsK6D#{W3Ef=hsM>$O!%oJ6qzaBkCiQ ztK!@6LK%@3tnzT|^^OnU##q%uWUUHClYRL? zOeyaUbU}qfI2#zoMh*QDz*$0+g3`Ra4J^lAt=!@*qo4!LkPg{LlpiG@2D{AyEKuNI zy5uU10Z=N+pFOgzFuIDDk$Z@YZRVjW&fKPmKlnB|j#XXD<=OC4b-g}yEN7~Rglw3Z zsw9BQD3(JQ_?e=5K|Wkkqdfu$8>dK_oRGXn`laVa~%RW_&$Az=VA>27?pQe1 zp{QvB(C%h0KY|5Se^ezckd&75z*XzNV{s%z=nD@B9(Otw}occ=y{tttZlrz8EUwi;8R7d5ha zy(uDAY4wKET7r)h)o7KTxt4+^BpqK%-CE0P5=(Dd$+llFxN$tUW67kOB+%)KTXtI< z8y5(hEe|8v>6TBNUvJ11DfT)1SbD=mXng&_2ymGS7X!5Mt8U!fF|7;1T&&%AJ3qhW*c{%%b^V(ZGI1BU>h4nNc5TY-rc1|&Bx0=P%(r)$*NLZg zdf<|MKuEPE8!#|L4J{*bS^a{(c*(`xW|fyvTe*ypWpgYv*CIB3Sc6{ z{omQ`sS($MQR_8IAqD~=ORgabp&=Ipqr&RW zhWEQZj0Fso-yG4zRAu{MhlJee%(5N$G817q2JUIT>b~N$op_;#0uRAI=j!#FV#Ug2 zot5JbhgzJ)ecf4q8uEqXaBIoMXI1n2Md+@F`OcXvtiZ`JqdWO1+PzZ2mw#4o0;189 zSJRsBe4FU~mOTxw*FwE}osl@kImI;nHS_G5?2VFVk*(5KecYn_-o?^Z` zw)ewzBO$(#@mFrbs$&{ad$$fTe*blNfD%{7Fn`vv0P81Zz4}iH-wkPCgmK@^3;Jmv zmHzC#>w=^6$TpP0JgUk)I~8c&Yc^5NwgX3>-7v2A}=4pRr|`l<}eG`wtcF# z@gwBV>9xqR2Y<`I9!RI=pZkhg(5?8C@~dpIE$?(mSikED?%%hIfKAM@3$+M+02)Jt zv|ownSpRJSE5IQ!t2&1`ynBi;iO$Jw5MG$=h38!z)6p>9?vn@^6nF2b-yt@5L#|yh zmR*`J%p#1#ooC*DvME+QH&SzYV#TgZ_sZ7t`-xQtCMgju)P~Ew(@#P^%}#xGYxc;?lse&zco;Etb$&BU$3ZjsyLGw%d}wHND96Wvp^BJ>Y3?lrDCtktD^YZu!K4%K_>wuF8(fj zGRKm@_Ld;EzkhhtcIE5Jhq<4Z*`0~pV#lZV!`D& zbGylAZ<*sFCc`X_U)yzhvl`DAZYiFo@vTiP50?tIZRHFQ6!+T9R2u#__c7@Bbtaxm%iV>>>l*EwBzkqXfA8L43zKVNj5PKukczX_tclW`e+xZouhBD(%A4HE34x=nk#n!fxNe zQpMe;dVN)or(-WPy*R&rSGmcTg$gLW5!(=4Gkp;JbnbjAu%7*N;KK9IPk)EBJN!)* zFosiEqK7ht&-a7iNGxpi$p_c=Rm9#}XT$M5YFlIbiD!SphtwSgPVn{ZP#P@crP+R$ z_xPl@8wB012O#zwd!Ti(j{e+;mFYiM=Of-7i+X^Rdn3y3B*0eEYPX47nGHVIV-h@X zmQ#;&RQ_%JaQE52*v*8kRN$qKKx?4}*iHGcmBBafVieCmDF3xN7j<}jfBnk_S7^2j zJ2S{UDmL!Z@Xs^z(~9xv&u7K{*!n5TMV}Sd=m(TXexvEk)Ns%5PloWc5{obk2$K>D z^a^jL(QaLWvhaevY-lEY+EmHts82f2e^O|#@kC2D{geSdQ-(1rxBUAI_e(RNE~c6K zRiAwb%+9VV^{0r`_j8J@oXRtzbSJdwE(%f9IL$*HQ(por;m_7`W$kyQWo!v{t~0!D z@TEjm|FaEo`{p{CCvKQcq6ihy^4|WcuHFy<;Y;DYS{!OVVUqrY zbDHo+U~k6RQ=I$$vKA>ARAiUvi_K2pMP1qR8WRq%v2G34c$(t9@%(z{Pr!jgxdDo} zDWnPWMq`&{L7)6yanRm%4gU7Es&fK#2-yQXy2lZ{x<#AziC&8sct|uD^ptN@v)0Nk z>f<-SfPbC(dN}8$*0+@~9p7We7f_)pi)1!mKzYyObZZDm^y8W-hjq+=bMPIJSV_35 zB(@mR(@=8GtJlH=0TdVm;iih|PSAs?4?^U7XRla)7&!_N-a98tWY{r?0L;_Vij2{!{^7nws6#RTvns%JsbtVJ>8icNNHp(*bA z7}3>*FcXBCZf0CbQo->h!_RA>+55)OOvem89Kf60$KqGnmwv5QSeBr;=^Nyc;R7LY zB2oUci*FZO1^AN*?#J(?ZO zzLx=hEa=lkHS10wA4c$=i4xc8429|EmC&-1UaM z9rkUCjL}sscIy~cS?CI6bpAqq<~)TP}nn)e(O!W~G?+HKHVa5!a|zIri_ zjS<@v{H2Eic;F3cTEL&RsMv{aQq@tTsA?I$Q+-!`Y$q$?tTI&tqU90(HEUZ2yy%XP zns*cx7W|+O3A(THiyCn0&2`xib=SB*yQ19G4x~<4IU3jenT0%@`|zVsd-(GQuoe8Q z$Vb_j4sJ?zas7c>EEZS-2O;Pu$`&}oqj5cXp5B2;nal@od%0CIlw|x@5>5i7Lymt2 zJO7)6(^x{LPMMU)(mQECS2oN*mu)e>R}l?=zx=oP9X$E$tAO`!>`0|hb-?t|*zK>k z(EN6C1VD7Ep2M1#{3G8L@Iz_g@cBD#YV>RMIA^|1z@F@qe)u#fI6 zlzp|sU~!h|ou|;x;iX!I@&d%+hWO+&)yA_+9ENKr4bz1Ho87P5jtdbmV3PI)r)R8d zFLS{6I5gV9tOOwwpzon<+k0csk=hFylnqP4%q*q#&!y?$ll4`A;<8X-Dm93j`#VCh z?sGc?PT%kY2H+vawykdIW;ysIe6u(&2Ie#a6kveesZ=3cTi*s$T!p6JC(dy+t!bng zAIYSI67>53C|RhtCEUVG%5u|?zy}P^hM-h{_V{E=&xW9Ty%+8QF0IiKY^pt_7u%v1 zvJc`tvUrYFubq-}y9aR3H&c)#jV>XNgr%3p5@o98ej9`M#=sG+Y2KT!&mhfLOc+fU zdMwgShZZ?RASS%P#Ne6u*j)}Xs0I;D$5R1v7??i@8aQuKRKs~Pz5i)jg>4D%ZDZCI z6Vt9kPt)l^fIExBk4@KU)#b$`g)$Q}2l5QpdGokh?RV3Ij#dCpAI*~r!*E9dLaSf27`X&I5WJN&SpdeD7&v9ihLeiBGaSlx6us@UOu$w3c?8*58@8 zkpq=O8q+4v&tZ}|-Y14n+E~j$4NT&@yf|vZy6EmlBGbgTK?;=-PyFTi9(w6*rX?U+ z>$z2E5@S%hKH*4z*r1@(;ymch;#S|aV)6~VQ%}eK=7Ar%|FQ=*2ZrXoBm-C|zvAab z3id_WR?GK9mb^yFRi0N9AJQ4%OKbeXeTFOkBg;efIc@e^&IEl81QwG_WK$7`+3~?g zCe8(V$L2`Ur2S6~p}q9cqR^3Q9gqh*=^7%-r&H@-^VQEk4sq)az+;Y}OF{s{u~0cj zsJA1>F-gdENBb@Uw-&Y$8!yis1J_lFIeQ?F_(2m>@g>vA1I8WlZ2cTzqgYB zKZ5VN6Cub+xZFvkfK%w@xLbqMu@6qdubsr~(8p0^0{^&};@f5+vZUQx4o$N3m(rvGSoIOvMGRV9b!0 zPqjM6UleYAn=(;iS*=~0qVqCG_Y*(8&$%+R%HVI4;Rmggms}bFljY0_V>5)LPO_<8 zYCER7a{p~{pTwhW7bhz~IK#w#ellDk&9NZU$p!8!HO*|UcJ`hc4s!`kL=f*Mm@UfE zH;2LXWR5>Ph*r7(2@X}9;~DbonnpcY$R&KE=Le7<26lcd0YZUI4sC!l}LkccHO}xJ$Psg85mutI;ni)K_hM&omiQm5yp$Ettkj87g z0<)(WrLsG5yk>rq7UJ;8Fe!U>nzD+!PrOWp3xg(KpAi1Qy|mVW<`z@?j%7KM=*@^X zbWfx(8qDUjf%G7ip?i|<-i@xmQM0+?j$qr*XkS2;*UAX{Hz2>nyv-|P$W^pHccUAd+ehKM?LucN} zL%ATc)+xOa&F8*9daC_FhpcsuOZ~CsUGP|Hr=32)-2{%Z&p6P0Vtnlp8SkTEl+1JE zr9Mq#NMr@Xo)T!HnQ}&g!vf`BEVTUg zuU3iPGEp-{nX+v4&$ZP(MI_SSrN)BP2R$F`(Eo0>eGRMFY{nQy>C&%*V!>6T~hp7695ex^6K(buZ3|JJ#g0JzPuVY7g) zn{K#s16f^JS4v90ETSfi8g2YFY1koz9KJvQpO~nbC-N@ zzEK?UnU243Z?7HP`s&ZzE20Ers}4?6Q%+=lUcYP9p7~YQ_xa1-fOi4`TI)S2B`@jl zj&3xeFM@M(kFkgOdI5j=3*hqL$BU(nU^f-*VS(14V@6xwI}UqK{{8+UVg~2}C%C~O z>wMh%g{$Y&0$EC-^!*T_uN^P54U0kzp8wnF|1-i4Nm-B%d9Hf`WUxi7MGffqye|ma zVg%@^yXn}<>P@bL+3SUYsFf#EAI#wsc%P~L)jN_&sj(^FGaqBTvZQ)+AMY7>^!eCV z{Ab*(TD=i0Ao)?8=X~Sgi4~)pl|3FlbfHP@cjt=}(sAk2&=zAyuH^QlP;eY4OKayP zi&V^bDsDiPKvs^ruWBS`>@mL=5_b?q8{UqJ2nJQ)=76HYx;{NJp2E?clYR71r%T_m zYR}Vic5qh3?!I}7w;P;%IR()ZDQvK(M*k-3z>vE$En}C%Z>8zxp2V5<^u1K=o_mrH zk%n9YhmLt?L9DLf`k$D5w`k17j%Ow{g0s^*BS*4Ps#w08^au>B_xHo&k+P>u|38|} z`=83V@&D%>XW`)3>)^5_GBYYV$KIRljy;l{m2r-}Lsm%kCZsYd#|%jtgb=b*_N<(* z`@TQlKj8Y|`r&#!-q-8>dOe>5e_%8Byxs#ZH_JcoNF;_VtXJ2SQh z6hOM@<_j_9g|he#<_aJ$gpqy%Z{;1(2qKyVO^?2mIl^`l&4aX}^V-{qPrm52i&K+4qm}r+W>C)5Dm&Ezj#4AfeQ=^tiL!y4k6yw6mbIbad z3xmt#2ut2IJ@L>Mg7KejS~N(V;D$-SHUlQX#)Y z2IeNX0|=^NWZNpM`_Np^R}01l`YVk=e)5;DD)f)>eyHjS{aEJcQFGj)?$+QJBx5g zGyS4xkKxpl3e|5*E_0+VMDrW z;VCbx{n`|d_2#Yxtw~F|&`CtzINfRgP;U4%Qt8jp@9*VTB%+l6ofUV-az5l$#rWX1 zDA-B}1&h@@QRgng(F#OgBO=qptki-fmGn9gJMFhejOFy7T6EhXvXv$BXIb)vbC>0p zCFgeVq7-J^_r52~d_vk@IF3Z->DzoSx{&Sygr#()bGC{Ajmi9qtd&Po6%P$n*embr znpjol+;V(WnQP-e?UHK}&0dx76unXT$gS*ARl%Ls>8iq|O!n%cfKQ>{3WJv(RTtmi zo34H`Ho;y~5<_)XU7EmGP*avdmhR*$eW1co`!LPKy0$XUv0$Sz%YUY}dc%XGuBJT8 zx~^66gnm=k+xXsDI5A5WYIdRnVkTYchZxiT)Ga5jayM5A&3vi3#PEr}KowZep6)}GxGJ_h-5VbU)hch8K1R{UYn zeGrtOSDwLy2$_>E#*ZXkxLkt6u39qg*%{TPInPNyZ~(p*dU~jvvw!nPA}nFad?k!m(i^Q z%QaFxtcO{mpx*`%ff*B2qu{5I)5u#?i}V)*(#u-t1g*CDf3(-pK)*>?=|vSv+%M(M ztmRI1cRgT4MCqlB3n|F7n?X1w`4UlMQk_)&e(5|rgWKEz1g>=z%t;*`c9koP7(KN&$11B+mklq{y!w+y>jA`&&+CAr@#_!VkRPzW$u`#>mNu z4pqOxTiGCA_SDoK=xuC2*b+$B`BH+YTZo67n51jEV=3A!;~oDKnjMtpdjkk=O91A& zzI2%ktDTj5M?^4P3?G+8klaPMc#docWZTXYAs1V^|074n7%=h z{!3{@Og6!U4Poi3R2UmCtqS=qSV>d_5NbO9mr!Pef(!!F0+%u_#?K`q(Vz(cjn|M! z2PjmgT8gjSKuB2{fvpuNV#G+dZvFrnxwSjijgiza3J{Y!j{Bh49r(xe1&05Hpdh|F zTw8Rrsn@cRI$anR<$BRk-K$tLJ!fv#+$sr-7ZDJ@C^1MB#kfg}kP|ooBML7NZ8G&C zMjl;11yu_yd$H9o9cBcUP3+5sTgA(iT3rAu1FMxLNG646Uux19F>QDp6wRAXQi^7m z9>-$NP2YZm1-B1~Yf-iErMtHhSnBdOWiixN#W;L9SDGq})blQSythgh<7o^FnCee< zYC+W0;-D$Ut4;c>e+8)Jnp$-%-bi;p{W~FM$ogftc>!Y}rF98J&FT&Cft~p06cv0y zerSj`B}s#tTIE7T5$B(K9VBOD(mf_fdILVvv8RcqN$~nif?Z;NMa7U1@XCdq+kjGr zmSiw7xF}U1&P{29v1I!`H4u4Ycf|~Y2*}6wGRY0akzeyU<$pQpr3p{w#Os(iP6fY~ zOS8U8lF6;eisQT#gUY8fO3>!GXh>#UU~%K)1HNE=uL^Al;_uVagM?hscCB$zqZer= zuh!#}q3aQ;G^R_>A4@)p$NB%n^Hp2cA$I(PEhkqeUX0UBT+$Mrec^QJXbQ-Av8(9& zH~*S{1%FtiZ!G`km6oDMSqP*3e`BSk6wW~Fvnp7Bde@yqu96Ne-bL_c{wN85tywFc zjlUra#H4mlY>6WPCo*^Shz0t|72eRy-tZc#_rvq}S6bvdyO*~QefqM8#RX{mv#Q6J z_^Hp6tUvIkD!V5>#)=MonW=P0K~4cjGKo7uCS*s#w|@4qe2s1kG4B}Lo+wJoR2+&( z^Pv(AVK0fRW*%`GQk#XMhfW6Pf?8uGUM)V@DaRe$t%!V>Ed^_7UvoF6y%lm*%bZ(g z0P$=k0PISFUwVdw3{gG}SF9;=4*|x&EeO8Cp6rUyQJPN_*X^%;{1Y#t`1kz>RHCY6 zk!gExi`3KH%htaC&W4AF$9%PKRyLWM3pym*(H7smXaA&l$#PlQU&FoV2O>mf`th!3 z4EAvTrGYc)N$WwitPosyeIj#0XBRS;m)^eS4B)@*(OoyVeSZ0o=*z+m z8D;FNP(H?fSTFlR2Dt6P%waPju8?p1FrnTKaf?lP0l{;#jDP={>XswN)Xwb*x5!-z zE#9QhfFtC{pqGyH=kVi(yuK823NgB;w{eoCj4Hh68$9IK zk7B@ia+ZYvsrVmb{LT{>nfzv8P35{)4*@CW|oHy_H&o;&K1#;(9vle zoU))K@9rYw8T|`hz&WrG;YzqX{$O`kW6#)e;BT_nVX>#Nh8f1(l8x;`uovAprzgTJ ze}IDo=Hj5>c;a_CD+35NA9v8Bz(u+u%M269?y0nEo|tz2OO5bV6&%8@e&m6ga7jTS z&NW|L!R3++PQL(t{v$`{FGR&54z)@?=9V(4`6m;P`=YjHJ@1w<#hL$0WfV2Ijl)BJ z<$O17__2}^!>04GpaajO^Z4JTLHL*>d=?PhoEGKdl9B9{w$;aEs~)7m=*Pb4nf1wb z-tN-EDSp8%49(F@K89ydkjGL7q$6$B43@#`7r*1`ggCr2G*#EZ>00rl8=buciqMR;p?aS%;AU5Xkp%4Lep)&oe&dv)JI5Vt*q>7?@g#h<$ zK@*o}4Ot?#eHU9-)*1*l^8(ccx)!P`C0>CtBJo3UP%WZ@tPv(rl`9{_AVy*N_ZwI% zS`LGQh4+{+#mWotLtjl9m=P555PI2hw){SW2`sOGrP6Pb;({IwuOj6QOepm#CdODP zJY*7&L7HKCQpb64LbiIYzieGyE&5#fsvM<-vPk9lo&j&q5+Yv!aU#Aw{|M1GJ z&?fy8JuF{n$9!p|zS6%A|E6x%r(LGp#fQ`i@+bsBIZm$-5tPd~F1xJ$gf>O)Q zt$*Q1&9f_KWs~wj93g!lX7TvfF1BMUE50#TE#{@gVz2y~G)1{O$QfD98#=a<9ObHT zf2p~Vf>g*pr=5zmQ3i#OK3SmGyj{gD($$?~-3F-Pd0gdsEnmQwf}`I>xW)ulA_#3* z$?jkaxVDB3TnmnOYix1QgR9(VA;_S6*V4vPEwE|x>tXb&=$%x`i)3pHMBNV-!;+%k zxO$DPdOnKz7}!ggH@xRby2nk5Tf#^Cm*_XT5?)k2fYjo&R1^bg7!IO4wOriIRtn(n z$fCw65c-%)zX%otRZ$XQ#_qO>n7XO#jCI?Ty)1zS`m<^V3hGwqNxKYH zdo2!re4liC^eT;;i@mK@s+#tzLgcuLf|)808)ODUs4%Ik^c2<3k4;b%tx%3b)fd+Ve3Pn9t06J`cFn}1XRY0ok zPP5%UiKFhxP(a3nq`Q3?C<(n1Bbps8->jR_w)XF2qmf0;)F2Osja4&(I!lULpSV#f zi3UzO!ATG~G=*?KxLn*lrI|oEM9QR$ua2&(DWmB=yG)X{uJaew!D4yLRLP2{tjzUG zrrFLU>H24$myZJPSQ{0u^*c9OsKzeUTx2jKGhdm_V&o5&9DL($iLHZ4bq&4ILi0q$ zkW{A|18o+Un+|_=!?$vk)$2DekB&6p)Z$E2af(RC0&jSsbz`H^uP4|99OkX7*Iis- zV*`4v07-G^o6qSw_>~(wb*3$x?bK3=59$ZYpX7^_fSO$zU2K2NSLw_jX%n|JqlUCx zLBENpD-EfQ1yELcGXkY#udLBG7pA6#^CZgbm|h^~xm~e zAdYn$RJR#gj$5WhLYyS;%kIDfd=c9uu5}!j7Lhgt1P&q4Y7w~>dbr%nVx4!WW%Lp6 zc2FO-S=E}EBuSw49a=gNg)I(x>piS*2mKXJV>tM_VJ0M&BKb7_f;_D7s-9lguW$>C zEC*!%biy(gpw8?0n*ChE)YWl)dh3$@6iR9MQr);*AI%`HD-1A{U4mOo{_Y4Ce34t zix(b{jsqeMe{YSc3XDVa*`eBKm=zkXXuGoVejW+u9?ra6vSI4ZKtD};k}5sc*}J;Y z!y}xfhykN0vm;&`q26aWw$uFuh-XD(yMcSf#azgw@m*AUyRRxnLCO^1;6V1Rst^5Z zqc=5sPrIe!8WbI)z6Wu*!rS%CIh?>fg`?&7XORK1-nkN?u%}!&D4Ln;QJO2h!Xm{M z&B-R_V#VSLqZM)%q;}^34nE(6nZ5avOE$$#tb;Vn?aVD)NEQQn!wXqgc1`^0S%3TI zx>erF$j(+PXM&ljNl*gz)6iM`k7U*^pTQp)P2_hGKtABO)jh#{JP_dO~nuRlDrG~4C!KWgoC)E>&;tGl~nNU3w;@}>iLaFMUU7En4yg>bA_SyzR#t#(_vye)-INXj-&Yw zJXT%ceKQ(M9+rZn-P8!zM=SJ(_V3CRc77-}%tQ}NsAfEQQ0WC(o@`v<_(15DJ(y9f zu(lNNv+CNX`-!#w+(NsKyH1fvwxI}~MRQNTp3&tPoI5nR8g3TK5^IxY;H_MYQ{xUD z!C!v%%`(=0O(}tAWmP~7kJCG%*(55WFPmmOo}S>*V=&AaE(mzJ7EP}z@q)McP-T#Cj0ReGqqcg))WwP3qubgufNoNbHps zi;KwH3O7`prR9zxA4kPVf>8=Aj0Eo3eOBRi{UvC_n21@7Z{6C& zvTF(hI7EXv-_&jxUuog*VlrMMgAL5)qs(;`X<8~rhF8M#LBbiTMc=;BmzyvGZ~(wV~1k!e?vjx8RrG@u=6{n15g2 zDWy4I1Oh#npK?^QxO)ZvrWto8miME>ZGByayw&OO+s{p$mw^G)75zgX<bsx#yJ7e-Rt2O1JdLG7n z$D+}uBj`}{p{Hew({S$9`z&{@pWm4_`FqCVZQBvB5qbAMtB?Kb`=>{Te^{IQJ7XwW z<-*(V;0IF3?D9c>+5DYJiI;A@2!GV-{J!u)DD{^;aGfGwJ5Mg+T8;Ze{YAQZfhg7d z^33CF6&Gi)_gq)#@%bIj5Z}ev2v+$>OsM|~kRTs?j```o@wxWa%O=jSpkLqa*dL#B zg@^2hb>zuEjR+4r{5kznGn6|re4)L&==xqW9gN5^Rw|WWTA<1256i7hY>zIbKxFlD zk_RD1B#L$^wGv92tZ0_I{Wvrq^S7BQ6JX(amGumXCRcq@kiSTiDe_3vVokY!jl?}NbS6BPDoRN4mDVa(sWekC`) zG0v+kN8f$5QSp_6jn_?6{v;)a(YHz4)IzBWT%9Kls$8J=X{%Ms6PKxp<@5`~IRZ4- zb~TFZ!W2sKOyHkXF~r=DF^qmyyi3%sy&G{F#6i3U#%*WkqyPw`JRPTdHEsNrVjN8# zT)Iwc^k{{`S;6fS#W_s~K1*NYQ3=NwuPH!F+BJk*_k%T=>7gpnLSnSSni?@(QW!~8 z1FF-BRg`LzmQIHOZ@KPESun{LX}3FtAFc$yBkD}U?mnMZCgrpm>V<7orTubF@#t4n zp$K@P5XwpmsU0jdIs3c7aF;}c4F!Bw!g~`L*2@brez2{7^L;CROn84icr_rYhdFOH zI=5B;?WMu$?nb1H2Vq=bj)M+Fh0-|nclQFz1ILsk5~Bk;j{bMt_(jBO&b@~C)zdhkGf=s48u@%7mQ{Iy z`W+e}hXz;wPKvgeO^iVW(o2^qsW2`79H^15t|ev|I{%TLQt7HA=DL50s0oTrxdP^t@#4ODnJ~s8mVXg}*rf;tuimrK#xGqz? zZ=1VkW(J7pe7wn&uW?DQ1gvJ(M}SE6C?-!R`PY;olz>65{r0!YCQK3VM{x1pA@w+G z6Cf$jrT&^C+DHWtI0}@r-&}+HFA!lS`1mWSF0@J)o~9*yJQILV)K^x)JQyOtjVPTRrM* z(a*(&;Zph2Ci|;lO};kfJR2r?fS*?5RZQrpkFJ_w#OLE9@W|_CnOfNJX$=!&G8ZM(eM)gXSAkgD)BGQTtY3= ziheYO(NQRosQr`IfOHH>*CPm6YoI5&Nzc7v8y|`PbY$1tC>Zk{l=Y5vBw`mZet>tI z-uu^=bVE#@2qo4G?<`5K7QFk6++`X1_{}rK5@;*238vezi_WHk*?cBQcD_ipjkI}9 zL3Z$oeJh5(6>v5<(k~Hi_x|>x${*0DEAqr2_q9}S6acpr5Wm`LW3eihjU8mrzHNB)u z{~WOCJzH*5{+>nM`k6x37AQMEd|KVL<;vJ!0JGX~yQ)b`wQ>yVZ|`r+Ogo?;#1wmt zeOGi;`pKz11E{)vY!;E-iB;v$>P2S^Hpa`?Muo@US~4q}9t+~Gvz|T4y;CtU)~xf6 z3gU!TS5!&e{l~z_hUL@aD?Ig4NU57UA;8AWXvb{b!@IX*@T6Q_z=OgL$aO#t6 zL+zP#IP1?}2EMK9-k*LOHQe3cZRl$4nyR{=i&7eUX+=+ zO@P<0DS>T0+7k49txj0a*H)vf;!&jGJ1TxUBT)duR*Df>?-apy$q8dDH=1ej4DO|@ z$_UtK4|?J9YiIS@K%cqzr@7J1ZCko0=MPQ-pVEAnJpIz7ye01Wf4oQRcS6PYbq#lG z9l9Z$p|39>*Ft&IZ?XTupJXHT3KUH*nEo1X4Mv-?_Nk#-%kvwVKtFGU_W)wI1_R#$ z&OTU%JkY2kQqe_&U}cc79?kT2Xa+6CQ%P_} zQ*OWBX4N?0+xaH5sn|^a zBz*_<8{eSQ(}b;NH3BHk@czB-96>~+B`H%#y&{Z=)LWo^1$9gW)ypnZKEAVC;foqA zrL!!7Q#o{v7#$RdA&1nMmyPwpX@rIaP`r4)%X@rzmk$IU00O0$qK0SxK_r&IbsX61 z^+SOYcx-77QiX~{9LyTyL=n}`nh|e*q3KHIa!Yx6r1>Vq*%Cg?CGUwm^uNUU5yzeR z2eqRt3Sz7>{Jx0=hH04UaKOg}QO&FcB%j1_tHjG~30yVPy(~WQy-ZQOhin@CtDc7! zUo=rbQlB8PIAC~@O^XtGsg?o8tU7>(rzaJwS zV=8Iua3a%G7KKSYkcucxh2M?n;D1Z0Qd*EORcLB?w3rB67Z3WEjM!F>GVXnw=nt7*Mu` zt;t>!!7taK>VK%g@H91Xv;8u+uzn&=X>e+^8HgQhh4$Xe6Jo{#FRvxAL}M|llAMp4 zpO4{GChFmM-6e-N?xm8tmrLeDz3yRF`Ic*Tvw{H@R^Y4ZUW34IJWxr>7E;W z_A=(o(Md5^T4J<$+;5%BPuos>`-0h4z09VYS)eHW5^w>{6Sjr%+k9hIo;*}20_QH| z*k32B*z5M%=0RxcTJ7t5?Z`RT&vN8j-?G9c@q*F#UFI+O(QH(|@bnNozua~1T*u3k zjuLVb0v1k%6i(MCoo=!?=Q%oQ1}UpdIvcXMn6mI|<+`}3y4+@Qb+T}^$#vCLb@gF! z3z&4glj|m~>K4V~9uxE{?4qfq>i&SmA zkY9MI1}A(ezditkrt}61LTKWj@uJkdwN?D6mrTO<1Qfp7+tl%0anRyip%yL0n1O4V zqK%TP&aUv?vvXB&Iu_Vjwj#LbX{CQ^Gz)Mp&XByhe0MQ z?dAvCg(`h3uuQWs`=Amcqyhq3iPl+lwv|s+v&3kzJ?LLNep52tYxJzH2NOiDxD!oc zCJ{M>zy>A$nglgm{aP5D@BWLm*KgLmr$lHWr7GlXpZwJfi>En4=A0uM@ML`|j>H65 zS!9iO#|)eM4Y;#(4S<3>Fu`M?i3F2PxgH{m&hO~oY^KzX)QPzI1FRZAP=ms8t(KbY zYde$33*Q=ta9-3J6m$N?R2^v$>!zwcO=F}Lw?Lh$bSm&L8#V-{>@`Zh*AE3HrGF3M zexe)YrQtDj;<597h8ye)t>)Nw)x>^EAS%$tvZX{_i9NS;e4~&Wr$M#U?&5B#mo4hYsnVlR?x^h$0-Em8PNQG{WGuQ{-Xl|YWnRpL6c(gYg@>l%=~g=@c+ zSE(9*QT2+{o1Kh2E%SH^UBZ2aW;2iy6?sEHEY>|E7d+(KugNbcD4xl)87^qnF7)>S z^sGy-Vk@l*STGtbKXn{4tZQ$}?mH98l?qs}9Gw~~&9&Rg(S?8|XXT+<#noYtO?>0G zvqr9bTgwHG<|N1q5+=7GyWm<*!wh=%qDqLb(Alg&)kNnUJ^4^5B+K@~IpxI|&X55J zu_BGtm2SV1)qDhgCf4~o7yL|z*W0@)^v~BnMJaj<_p!fF?`g4bgauKG;0hWuAf$mY z(c~Gz@h!afZFIp(svyK8ST^QsHylE0uWvJ~;270>^AwQ*_tJs-)>r#%4)woJ7Z`5S zdv5(;jHEZ(44yH$JGeLsz@_@i7y_Ws=KEwf)~@QliP2{HP~hMfb?4SQT0F*u{zsVl zhZC{NDdaP@0J&0`N_t~a~&2v`HCNZ>gnE4lhOI>w{*-__LZ$EcLg5iNswfC93G+@f8E4G02 zU(mJ1-=mzbHU9~I;iRIc50%Tl>7PBnWw3wr?9&C2-N0Z{eS*;ASDv`$igu2(W_!?1 z)X4vpY+mCsSVXIDFll1Y_x-CFf;MwO|4`@e8(Dmb$AK_-Wgx0`x6WYIvtozPaP!63 zdX<2t9rdbn<2PyuuPY(<=Zl-3$W8;v>&UjIb&-me`lpG#24h;# zP#FToc_Hrhmnn7G>F}}Xl8BiKrQ5-^-TrpHA^$Y~z7EuD{^;9f?)-R?s5DNzKOR>Y zHh_a$*uxd-2kp((IG@f6&QY_l+9DVa&7 zM$w$=vC`U)yGtvQQO%_sbv?}21{V`HC;7K27$FeqXeedxI=uTipT;ix5|W$9nac|a zm-s1HKwqY)fE0&UKp=)pdqu%c&#(H`&bkYM6b zEEicRO1&VJrira&0x<7Hh674XsUbx^1Y1Wm)_+uy7RpzbbexKES;e-Hgtk5YUNkvNirvenikoRvWv^9-6eK zRUS_pPIDi>1(sivHi{K{4*psfTKjE$6yQ zhS0!&6V;7i7aP@Ck>8v5VpX7>FghW<=8)rse13h#aGjQiGGDE_i^?NPd_M*xb#Vq= ze|54;G_jJon)2f5W^HPf@s{8w;clSF@$JIP8R`M25&5=N4g(y=w)pS*D!{y;#HswuUnQG^rVdiVidB5j8repyN^#P z-oqNjNWNlMPnVxrhkS`Nclb&zg-bOa_cVJh7q1x6Y^2JoI47qsp_cE9;D3;5nn0-~ z_KX^rt2c^fU-*S0R=r=A&^u?m_^iy!*loWoGypWexWd8r;J&gZi1L z7}o3ymFdk0)PAXkZh;A})u=GJFU=PGY(m(AH(2;KY!Kbh2yD7yjEgyvtk93n1}iQU z2|X_KRUvuY5zsa<=&j_f6DdzWW7?>A_3zNe7ivz4OQSH(S;;+^slSX9^$(q?F6Bt7 z$kH3r%?O%p{MOX9Gom}*smWv)cuVj@h_oG}%*4;9J;|3{jP~f&cvLwgX4Y#=jn%6k zhiq!=ii+gkJ(_l}j#x_cdim?kxskOBX2$o@SlVd)gPpE+_YWzCT>~MuSkvu5 zaiS458j5wi-EqhV7nvedo+JXA-Ttr!TFNQ9tu+{?|S|->%st9|2j+A~^fyn^h%=u+J39L#>da;c#zXe$3-P ziRQhhyxR`*6t_KuZgoT(UmTnM07&&IoYbVRKruCjsY9;vY;K$W^bc)#T@az3#xGRE znO|L+bp1Q{0nodyJ`dL(QsLOUc~7^3k9BxR<65hC0y(upKzKU$8gkc*8Q@Z1-DA)Z zb*G+Z)5f$dYPaD)w?k~o1bB^TI1Qv}XDux*xoN+%p4rQ7zmRAL55KcN+sg}hS1Flr z`h+T5CEm?OOEk;3z400!QFypvje_94ZsI^$L1SU`VNX%fft(Haf;5o3D0gK~hTR!dXoQ&z!2g^0S1=B<%WxvjF5l4-SiZaSX} zW)7+p?$sIukC@so9aLj!>WmU}zLaq=W0myl$R>H4FUqeS)*7YNnN{mds7N2yS-!7} zs~eeU3OlUF)7;U2t~1%{Xx`wiUvK?&Wb(!4rv~4&dfhplubnf8O(Ev>w#Or1Q&$h4 z5@;Imh{8{AIF6cM3p6;gzMC4n7L=Qq*5J%|IyGW_)SCZZ%tZLz^jNF@vl5y{cg;Ju zJ`^0a3Gg*~-g-AP$-(@*IjwQdR`=V?%+U+poJQ|^Dc|PLj$V>puXrb<%q(ymw-4!G zNltt>J0^PEF`m{GSg1QUq;uRk^}gwD{kyq0p2uAaG}|s+y7TSH$FJ7)CG6k5vu~|C ze!Y|S^wu}s@AV_cZ%*DnHTwDPd&TB)H;A@b`wv+c|Cs88gf#HIPCdGiBYM(B}f>s;z_kA$xqUCQ6 zHKcu(?=XshsV|_5cj8iMpwSveii5>NQdf9)Tm?UXarDSOUW-L)=N(7pQY{K(o8Ed) z(CN6}Ptp9hqw8#+abpyn16hm}UeLjUG8&@(r)7h7w>TPv5 z|E#dxI-M|oA=Tidzsfl5_z4*%mHMN>fUK)vjRP#z%bji{B9W%=-!G`kW;S}6T`%OT zPY+6D;&KweyTPRfrL|+{QZ)Y@lmUlGYf{Uxn+J&dMH5Y|p(f4>8|TJ{4HCiC%I*+mVicQ+JaX0y5VJ8o-=v2`av zWEAg}#Z>xHnrC>4^FiucP36lCK7*pRJn*S^#Ya{hO638D^sGBXrl8|EF)+zoz1qCRAC(ix(DBZCVOS0! zxC6f8n=Hjb<=t}+A&rz`feZE`n&gl&J7540Z$UV{B;lCA5DP4oa)Mu=5mW{bOCu3t zNI1t+7J@5oB_&-#tRiDE>5``Gq@B zigpsiM)5B~Hds;W1TK0~^5IaN+$8e3CcP`*bV-q6H3USTks%1Z@VB1U=IQZ|&3Dy2F9`l)&*6N;wpCTRuN05w)Dp+|Cy8 zWGV+S?u~bUa8b1<(?2TSU@6Xs{HMU+tq4$(GPJbO92t=>n;#*t2&tePC^2Sol7&R+ z-n@k%@w z?F^C!xcDgn%UYN7k&@piGK90|2@p$GR-e%80J=40FvsloB{0Q!?;#+ze}kn-F$cX_ z3Z*ZXNiLW5EWcJ)G6ApbQLH2{-q8(0%19>i72Fn}@)e>2D2<@u3zW(%iSUtPZ(M9R zBDq`9OGm>OWKscwfTe_}Rdg!B(y8z9RTR>B#mGV_*9hv(N()VfRguSGGpO)uMQl{H zCNrgEUdZlO6lomk0Sa_WuJRDQduNkH9UJSUk#e4RkKB`7p>xwNsUk-wTP2Jd%;#rj zT}Y9YDH&f+!B_PjXn;!P)rOWzR)r~@R2CI5zo@IGJ*^<$rLXKgeMr`35Ik`n!c(SL z*DZwBeax-1;>~$aKoKU9nq0+Y+4j;s?%r+b$5!v zgTdNq*v&eAT=iZ0LJE0?5YfjV55CAV9s-q9v<|}?4uEo@BqpOUnF?rFud(ZF&fLtR zz5MLPt+w}JZA`ma@*9EyZ;6NNElaT0dZAXPp1g28$O>HX>#R;ghhDAb0?U;1wGL1^ z3;{J2X6nE<`K0Wu6wWKn~KRomqk=)7EkEcR^67QR?z>nyhc+I1ON{xl$$+W)b4tY7WO?y~Sb<|)<9zuV*Q(A64| zVrX(wa6t8h->*>DwN;p*(rlfDG=qBf=&3I?puW)YtTXIHi{3xwLPD4mmr~1EU)%Y! zd4|(__D*|LVHc}SQ++cPOr#X=@oFvZRf0u_*h2Ajt=QN1K^D_2ltymMp|2%$7$lFQ z$-928Ru6}-G5ksJyKD6ZB;8zJ;w^tEklcK~q2y(ZOJbfL^{ZW7^wmOU)}loAS(a{_ z7O8NMj2B`1M-w9|l@U!<@`L#=KwLx*QtEXVgh5=jDz}~mK zgZeiTocR_ksKTU}NU{DY^?vn+SJOgn{Zyz(G~5~=b_#d9M(Mq=M(II-%4WbDbaL4j z0$_kDt!Ss|PV$u!H;Yy3jXTd8)~N#}DfsZoi>y>bf&Hg)Hxbel3~Szjc$h2}YKjj- z<@Z8~6+^yAEfC}ikgB&{PL8_3H5k7(P0~|H%u41ZR%57YQ7H{K{GJx|F*&?9Q+%t~ z@t$dS;28ok2nSyw#E=LtlTr4m;m#gcDZHzkUoB8tk3PcGIKM=9-h5Ro$wFm!;yiZ0 z`2JDMn+3`NUHWWMS07ApgJ`66J~)td{N=*?gO~kBo}I~3d5#(}@Q|=pA?mb+Bz0`? z-`N2s9PvW(o_mdfk;|1i0#tP?ey#44*so7_ke?adoqDjJ?RE#${y7iXewe=ZK_k~f ztI_#IA+yC!%rkc|B_X+2__cT*D81hKG%wews>}k2(OIQ*zXUL6j5h@#!3qp1Lau9G z0pa)w!&OS&X_f%|S8|s|Hi6CQOX%l<`|04vPbR!3bK7&G(u$~grx1-Laa_%Ol1S@+ z&ZLqGy}KU_UORfYG?|F&`%s~VN>D^g)lIYencJ@+AS) z<4c`~=zuRlvcI~8yhU*7(fe_^1}J%ly`Xx9Mn&cZd*F*LwGq_`-$JVgoo%Kh2P4zP zJ83p4dosSEA5T7y_;#TTq84$TnX8-oH#bKa%3lidrn+B7gA#pwL1!&|G-p%zemZRc zeY3O~yTmlOB+31wV|j^2=!ab7k8HIcsQ4c@=6{5i|A4Lj zP*Glf2V4H9zN}Te40l}CY+5!rU$*L5{tH_%qg^qvzinQ;q8+(%P`P4%W!ZM#{tk4_AA8kNH*6H>=AltNyf0zVmhgk!$SsYqN1{;a3*J?Cm1B*Y*CbeGy!b zHz38%+a|nO=Pq0y9azt}QkHIDn`ytXqp;EEvQf|!l>f%2@O}KEeLM+`E9HXd4;QoS^C6@=%kyjr+d;jXOBZ@;&qK{u{aScQQ)e^~wGh z3B#}7|G7W>C)WLMfBE0?1HOfu|CZSfAh=88BuH>if(H*IK!oJSW&iis=j?m#I1l%2jqyFLs#^8URW+-o!H!BS zCBMxG*CkdhkwNYi7-6`lk;<-HsFGv2ua(Jf-5-H4x;xOx75Dfwl4JBmuTU=JA298e z6I-cj+_`qN9=*ITqCh^9*5uf@)})?;BG=@^w86UX6@ z?c;N+Zoe}d-Mq(NZTdt0{sW;myFd-`uF!f|ihZ&kOJGolvTD0a!rsm^ zjhHxSG^2H(@BUK#lkr09+nbX10`dYzn?FCtHm8f!i){Y>o}L;YV0-Z7pFdTnXP?K5 zp4`34pCVbnz27^G*m;Y@AyE+;{Qk$%4T<}JP+t-6jO2$Lp}MhL(6pdOoXVO)E5tBRYLym|iUL9o@*xUspERhy~hGmo=zbALbh<0r2nrb5;)*)#i5 zNvaZSO;P;qYnSPf5*AN`?3T^lYVss3Jvtm~*4^#~t`jW1$JskrpAD-1X!Tifd~C77 z)fAap8lc@_%sBnY*hm67U_i~z{5Bg6~F`TC9pM3*0 zqqzi`56lE&6`(Km;#gyIdwVmk|*ww2Xn2NIp&r4NI4h8(MyrJ&MN+L zDv8|aaw)Tn$f@3pa{66bRuuJnsF3xjGzqz`g3$N!_Tb&cKMf!2@0Pq_KUvc|2oKv><@fjQB-Jl(&0>hd+NV0AB^q0 zvoXE=FutLnWj8lU#WbnF5b|rqNsl@tRm)lUr%d6%U6V&og#4y@y6b7u>wlC{%kIhv z@gLuz8?;g2Bqusw<1$5(h+?pKw&;cx4g>WF>P$jXDRZro`cep=T}e`ito_3N>(ID3 zh9$vKuPLuHJ=R>u{nnho*Ns10r;HEa;`Dd{`Zp5IoK)m*=(WL=RnKDe${HJuO62D2A{ z%+vJ(n~h6U9P?8vHH>C>GT!nnaG9@Z84b>73ii8 zR3^T9It653$Pu*Q5M{m6aZTjPofk6|Z~Mgzm5ViA9a)eVHD`uyvnGAT`9d+?H3R;o zPOT|yF8zH(FOYUZ;mG9y{yt(R@J3W&D&>BsCi8fR(_9g*HOcda6k-ncihHK6iwd;^ zT}UyG%OTga@*tZ*qR+TQHq6Up>^)o_)xLDe9330DcE7z)g>81C8MoqogQdeW}}AcwF~vpCBCDWa`_VVd^#NW-+hzxTluu?Q8Kkt0P)C zfcX~~f)4-!_#(ldK*0M401OPk0fYbdfebhv$OT}zKez+n!00s^ixorh5EJRR zW#ri;HJVrk30a$E=bdF$i4+Wsuz*?SQQ|@w8KtN{r3U!nK*{ICC@Ksb{bd{18Eq!T-x zNvz>pIlsn)TICOvZxM1+;>W-wx^P?&0b?+lEwoP+@36}#xp5cgCF#lOt^bz&_~VO- zjQExYipeazajVI-v-#P?!F4IVoKWr7Y6i}UfJo65K+^-~MsmQh6@~wK@YG*37y8c@ z2752#@;Y~m0vh7^-(%|wi$Dd`oKL^}>+Tp9P?~P|=nWO2y>wx#!A%+;+jr!3IE1rU zU@!54rr&<%xf{IwOKpa}d#TF!8p?RTw5|B*IFsVN(4Va**^a+?B=En@ssj!I(g8UB zmsy1dqZuC0ZhEsijz@#RtXflOwWQHF>N$tx3GZDdet8opx4F5aOWHD+a;K&d}6Y~woL^yaxhpA>rQt61fZpCVT}pX_uE zq1vaL1ARY@C2X*orm*Rjjz~)ZF25iq%tq`l%NS*8RTVfr;U!8@#NOnRn|l4dCzl5c zaSs~g<$m8Bd>-Z$eErY&-#05AGXo5-U&Z_(9XCMZo{oIhyB&;X3Oc{nPkar7{#T5O zgT;X&fG7VkX7<)_BCpGNXG-&~a#$#wRV!aZ*bXWdDB`+^;ZPn;Vq*XQ#_0RHpX_B6 zP#m9QdhC|gn4oAl@umUU=uDZE!N?rBQS}rdTLOz}>`sMx)dO-=x=7obM`C6QuV(FW zogbGIX1;=Hr*N&b7*z;4%FI;}cN+N}b}2n(Q6mXR3B>MJK2u2rgC5+QH_;aJn(`~X z)z2m@Z@{_MOwHq1$579QU(z=gznRIzu#0+i-Lx$CF>M! zaj`pD^k|^}@9od;C!aqI4BY*{`?p(RgcAQp|Muq`@L&B~;J1+b{_RDAOKA{CrHf50 zpVs(JTz?;I*Ii`B#XN!kRa9B5^tmKUf_yB@A(@d_lPyM$F=j78OW>DT8q-*Hd7Mha zA#1E;CYL=%R*mAnGL1OcA0P=>`j4~j6UyMdY#ztY#$Ehe8PD?5pUF%mqj5A4CuCVw znR=3ohy%T*&;R)eC^kC{2{Kd&(O_G?0HBYhUo~m^ZV{(*1@r93up~0(s=7Hz=J*~N zQi!OkO=qLaDBhsLOV@HQ!x?2{1_d0qu5i}k)CX$Yc=nGh;}rd-+U_$;Mh~7;;A+nz z4&y^KX(1cZj2kHDPxgRfbG6ELB$dEsu&hJmL%*R2b^J+=v-N#ZF1KyCQzSgw(}>{o zc%{W`4J^7kXXGasE92j~Llq#V_pFiY+bV+|oU@SkX@*Gk8)vTXbDU?@4o74M=8G%O z(+-a?RlAyU0ZLKoo%h{)4Ef6cUuXSSvwa7{_OE6;S7r51EMNQKPMpvf*KWMnvdeCQ zi;qgQI3IRY&4zFHK*Kdq3US^yz+vnG<3OX!YV~ANVtb zn?cNCYS+(bnVP&H%^*FC1K4g+BHNh*iY)J9Q(X%0XP*b%fziWiR)Dw65j9YwNcnLhCm2MP!=y4JJzR0o<`p+x{x;pM@Z#* zT-c$>>(G#KOED>LiWVZ1NJ~AlH}s;V^i!0U&`FmcuD-z80n#p~3!K#VE3nmZDn^}y zE@<)EWi?v#ewV!TInGe`+4|gf=9U8wTT9E^CF{-$bFoi2R>9-7JZtaD)XOGv2RnWg zpT*c`y`}ID3>69Gvu3IWCo&b3pg@qskD8 zes0b@?-?o1gck=jwuQm}jDIQm^cT;?DU7)GaY+bARCQsjK%jG3V!x(Kd8(2YcR{9& z^if4N<9qJ>9O+}uilA8O-BLeV3;R;q|IXa5V8Fdry6Au6;V1G*H!cp8$7-SxixYg? z%j}?GP@;^vZP2aLxGe1txvllsbGcOPO=7A^U_)%7HG{c+;90(#bCeCHQ9KSrq8%r3 zkG#eD40h^|{8H>lFP^i<@yg!*O>h@`> ztL4k&s8Spi0~RnjSFK!Th!kmagVb?%zaq-pK3#lcJI)9@yE)wKhJ0G^f7|iZE{y5W z^qy$i>U$ge;77BSkFd*+Qo17DlECk?t8E`pP~r{gfWvtsqaTbY-=7|x87GNsOO-MFN$B^DRvgSRO=@LBJp`5wgc(4 z)JS=lqFlC>C?q9O(fB!)`WQ;ce_fZJ_eLiHklq`;9)Kf@p+*%cx{^S_W}S^#EZ{fc zIeBKXEg%|vNhwx+0t7}8FF>$W&vxZ48R_KVnuec~a6u1@WgA5R(w4sk*o`HNk$~Kz z2J24vqbEZ+gv5O1njVMY8oybHG;)#L(*!s$I8Aj5HWbI?DfA+D3uOF&1RJJ1D;f%d zSk4LPB%?||9nZ+!*|AtVbO)LeS*^7qi0XNHVxh9H3fvi?ibKesc8Kf)fWZHqMy&4N zfayMP{tZegvVjSO;V{zDcknIra5M?77GdLVVxhF5ZvfMlVl;(J;Q1+9;~RDa@PydL zR;ajQ5=huU|0lKBVI)*WpfuoJ3wx|&pc-Sfd1|pLxm;Q)Hk=d3pcIZn)0^5_t0RWj zEFBTJHLRLx5+nln#r$SD3iMp-NOQ|^BTK|TTaH)1k~r(x_x4~JG@4lM@j))-p;}UO zA7+E+yk{kx@gWe*3CF0Dtd3?QcsYu3A2|$05V?ZdkMJDE$r?gNkdqe-|F^B`mDchS0&pHMm2l9tB!N( zNMxAte*xt2B>{MB$S5xDTB`3eS^$g{2z@)+J?MD9EzGGs2sqIdOAP7)bA9sv>Ta~9 zNf7azMe|=7 z-1y$~>;Ufne6bo{TcP1Fau&XcM%#NS8y2nnfY}n&Fgyyz;_8di(QtC**r~&m?TIuN zZ9A2BBB5HL{Pz8_HAuy4o&2|SSBJ~d%5y}W;}w)RPQ zj7MXwDfc2l;37k}z`@+My0yCM-mP@$o4Spbrf$ea3)%|Nc+-pPkQguW zbEM01s)wbl0Bvhe6b{nzkEi86AcI;#o^EY@$K#zDUUM!N;sCHbWs`2{mA~)s+U`!1 z;%I@>-~{AO_n1%Qcr@l8>@QZX)bd9uKBV0${Dm?LQJl~0+4ChU9t}nlJlfOwEaMVI zJ$%DR%xPFTx70=;P5o@s>Zo~}ZHO^1_*$XsqCW0s{`=3>6n(=dfkT79aj73>-&5VX zl5ug_Q{VwbUME{+#aeMCr5_)p?$e4Vt!0<<9=|Cu=f%_56e<c8{I|Mj2o|9W5z z+zL?^^DI2N{mfpw(JESEiB1WBtChW}!;IOshbvt#;{+*>j)b zcO`C7Fka^Ds+=z^Ld8 z4mW{Hb5pa@@c8l}8KJMsIAUyW37y8to?wb$i;+HaefjWu^ivp<>

8bB_H7SmsI_SXgTyH3VJPN_8+2U^8qv*6!mZH#}dX$ z=I}Z8-`LO2-!@$Q-`Eec9x32@xce{c=Mam`>|B#l{~zpkkhK@5t@c0I5AS2TlHFK& z=Koy(joxc(Sq_yo2f6MRP8`lI?c87TeIq&j?eC$a>ujjh!TP$?)@a+(lTV3G@i__k?*a>^ zcE1>ean@Z75k5S<7>29!U5-#ZcE22@ajv@@qxV0(9B1OZFW<3c#cxhJ}f$?MkR=guC!p5$)wMr^=mYcve0HjYw}T!j2OY|@kOJSf>G z{UBfWmHZK7`FMlt!BhWb?UT;03vq`{wg4!N>x6)8W+i!0(0S*^&KlG_pBYLFOgB}$ zs8nqPQ=?#{e=jzpHEusz{$->}3Uof& zYEWkcj95zt_~($O16{LYkYppta%JWK0#v{!$I9rO`(e~jX4o`dDtds}^e`y4X9{pJ z*Bzh|=68r?kcYYCfb>K0nbBCsYBUa%0)>;ojRr5`Lg`HpLb77egm=PNC?XIFGQKFm z&HBmocS%4LXTqA1WsqpEsWFlnrG)STh!Zq2yXR^S;qxgEPGf*Lg@d8AnT>KB-IqwF zO)JMzOs|_P@WF4FkCfz?NNP9=2Q@(m_L`00z}UtslovYkHAX1a-a`X!0CDNXm=@JU z%vQ@3z;wLZ*DIB_ooky>_&bOL4#05**gIyU6hM5y6fl=P@n|EkIuw{%cv;Hse^ewH z$U)VKg92Dm6U;;aa499(so^mYdL$DN!3LllqY35v*(8FeAC7bIP(h-Y6vtWPvy)OI zkWMc(>u`~TLpcCJlHBO`()eDbC=Ec5*(OAFR{qY_zk>=PALW?43_+{CawxA_GQpBS zn){KtdyxcDDohy7NOAmLCDk%%cYmp)k12G6WA7O zEHcy$`f5%6YK<#BuiuEj=P?`4Ev-$xu45wOz2{jnw=`eZlNs__eW_*Yn7?kwYRx@l zj9%#v9B+6<0#*?G7;19$NInL#x2^V(0x;v$sIlOd_Y2H z^uD9|o7@QtroXL}`}usk2+|)EyZzn8CyPm*jAihs9P(CTW-p>k;7B zTxNSEJMzxr$AIk%pLF+Xz@inM)fyQJLh2B9FEkZ-AijVZXYg=RHya{9XN|14WPa9h zBojAe+RD5YrW%P=1gV7Pq8gC_&Tbacf$6cPduNE5V(9LWX}eA*hh)hM=wB_-+}pm> zfN^Ja*<%`q z?W|FMZ0ZJGYDjEzG~+)p8}43is1$E72|2N@vRLUC@OvB1?+WF+cD`k8Zx$b3aqQ_@ zn>iP5Eo0bz%1`B+Q2C-Qt#2-^J8@=x`FXQ`T+htRm_OEX4nIIA7lzuFp}~gHG$x~$ z7k`QZ0pXJB;hw55obb+7b$h>9e>Jh7UKyJ_lQ*7397ugFDo=6jd7ITI;W<`_5)yJ& z!$xvFcY?SAaHvZGAaEiY-|;TM=1R|Nknhw|TxVADDH=xSGgJw1HZF3L0Dz`YsLl*? zMJ((2vzc_;`Fm;;ZS>4@$2-L*oN4SfKD~1T%^m zkMZ*qey)BFJe@fZty2WrqXsaadf_-XO1j!5(#G^0WHfqX5nj(hM*UF-1yX@M$^iSp zXu8RKbAgjw-Y;J~$IuQP@gM{j7*|O@%z>{PB3wQA+cT;=LMO;+_9tk`+38H`iUZgP zu$^uM9#z>^sN|tW=E8wPsei1=+wn%=dq27*HHMTJto)(!i-mOhtaLCGP(U(?K)X=~ z*4(I{V_*5}pWgU8$a_HU^uvp!e>Pt|y9*c;`M}s}H33TP(uc0)4t!s{lg;?spCeMo zL{R)iCIe_E#Rdjs%O$4+!~GFukDY*62tvg!IRa?R1T_X|rbfsaT=?8B@$8LCb3`cd zw5kh$mABY+#eJ2fT9rv>l`}&Fjzv|NU#Ms6z(ODq6-7FIJH@KVFDig56966>0*%6%bO3@)5a_Cx zC%8cNal{jvs4+h|cPzvT9VD6_rsbfhi3QjJ)NmpZkyQvuq@$RFvV6I+Y`Kci>T7Wo zJIOl-;LA$+1y0Ax#fZ6du$54>-vrv(#oi78)b!HDLuwzcyfE8BzR<8_%9I%c z%v)8huT=Ay)k?+@QY#485w&~+Kwl&dO(XE@0Yc8j-q9<5oW_^A3aXi`W0M|{MH-tA z1WsV$hpQ36;||}V5nX0bdJVsEYTq^W5O;vMqtFZCD2K09fZNQd3{t>{wAd`~MEw@f z{c<0IRfJ8sRz?%hl}TB)G92v^kR6KiyEUl|rv0Z15&I=livyi%hR{V>jcNdXRwFE zQTRvCB%}2^z_i`vFVoZ@RAAq5fqhhK6@n8PdE;codEr^}R6BVuA=_IX zG7H`fu-?UJ9bgg_GyvfmNV}JafXsl|cP}!8Ulm zcP8h|C2OM;;F@T#KESNlzIn93CnwWxHCes}p^XY;&(X{TI@Gc1WOR_IM5RoW>rCzG z%o-!;Om%;!>uylU86Z;W0}y)-dgr)ML(ME#eE>g3dw?<~%Qo+ARe`l6$W90ZDFz5K zDRaUhpL1w+uwbD%^^f<{|H7K2SOA?@8Dv)r{m_!(?ggEg z@a%e=>Bt0zQPdJGX{Dz7=pcg^7sBivk_?be=ac|#Eb{mLd^iRHXEI>QvDKV?WPr}h zVy<80dA0WgLF!d=2i94SHTtRu$nhX^bG(4@CjIOw{;rV`aCfc+508A&&uD zY)Olme6KQP(3L#Ajrkr*){75alClspcOWAXRU-)qFYDGDR}l~#42?B!$qwb0gXF4c zTP$R@X0^5I+?wg#wnkC58S#CiW z72rG3vWAL1>_^{y-I*BVVxf`ca%qYvWE9fazkOKD3C8 z@9hc&Fi;Wxe8?RCCD5LaTDvy0xG6+ z6)omuaO1DnBBs!?ANtt4IQeXY!TGKcjpY$np_tJ9(64*a2az^)Wj476VZy%AQJrBi zhgo=R;hdcajlGsk?{KN=w4Bh=&Nl`4>=9};h}_@)MpF%Ihofd*nPnCT%3hFE2Pn!p z3D*l?AQa^&S?SuT>yAO<*1fFk)zV&#FqX)p=g_bvv^0$1=Fvi|O5~TI-Kxuf*gG z&%&k6mmB?;Z8|qM7L#+e0dquC9voW-F|BUbyx?vUsIm}M62WI&-?hw%LrE=Pix6=t5(X~+8 zyH5yue}K#S_B_JrCNjE!6zB{GLG*$0trdE%J5Q%K{}~5x^3Kv%XB%1{I2Rts;a9wl z`dZ}fn zF;3|2&y)HQEpvDsOzds1^!9PMkBDiAk!(C)$9VFL0|}iY5n@GK2=%!kuI0_=z*n#7 zJ?zbxa?rB%!_!Ax=O5mu)mxAEFj_-l~uESRy#HeD3x#P=H%4ZaN(y zH8^}{$&zmP&D9?&$N)|kA2_vAx}-+&{$$Gc;IB1Z=raV(V8m+uW2JVY!O(E)pD0i+;sC=8_r zN8S@H@p*uJjf48gk|7*B2{>TE;a&;}tS59-JsXyth!TqUZ=&V@;#pSdJftOKo897Y z><&@=ar7>2@vz?)M>>&<)!QzD%?=B*MPflzLUvwUb;V9QPytirM%ffFduE(uE({MZ zln4yctxA=Fr|QNu8P`ILuPYf0}6pq zZFH=Cn9hh79z6>I4PUvk1()b08vf?V9jTgueJCEC1aDgB!9*r{W0wA*19v@#l18l+ zmaPVze1Z^|AniYl-Dd+5qHH8d;=O~E=uz0!PdPS!18>eg4n*G*Ek_C!!b|DVA6$Ah zROk3d$GH>ni+37E;rDvhQ2b7eARY`nNaadK3ni_u)}Zl_HXWL&%Dq@Bp8k?*lvpiUxJ9SvZb9!*oj zTY8#!CJA~b00>^bAG`N9kvKJN|7cNc4 z(n?CEaab0^m+S)Jg9jeo)sd!aYqUg|Vp!0CQh=wtw&19kk?zBNH-nR>f=b)uWlJK^Ng;hvBC;Nmdz3a*^uH96S_?*5x-+w%B@LjpSLWPwvd^Lco1RV z2pgqt#m9v4iD~imH={l$HtG*Aqu#QaZYJ26v4E1BFT7Y-A4;NF6s4N6PtKE7xrWsI zm&k3BrB$UIGaldbEOX`i9xWRG=sLg)z7lpdIcUVV<0MmtVe2_Y^aFX_xla(N>45yCsd>9XENi46FexG2f0eS@L#Bi0H_T?^>rID|rV>rB& z)7g%!g7VN$-|X56W<7T9^ILi1Omd(vL(9ZiHs2KTz}0>2(U)W!03MFGh{8%cd+eBa z35YMX`f4Rmn+p`qP3K~svZI4ch*EhIz?{H0q1$~SVW;GsJ0Uk{<||AP8po9_wE8h2 zGv8%RtbWSWe(p(}E;Aa>EXB9`G26I#vGpQdVxAC65cHFf4Tv(pl}eo- zp&Xl6s-$-@!eyFFfqT7h$9rQ0mN~T*MTSptfQ7dG%Nf{F zQu*OJHwV@e8Y6iEgk(;!2n>4&wdeiC7qt%|=Q!!#s@MQlu740~`Q@m9FEYi(t zKQOIvN1b93qb^&0iT8P0Jd05BsS?TF;~}c$#^{f()$65Dyns8H@S#Z!Hz79$K?8WE1l!2o<5IPEcYc=x;{jD>SWVdADgap&lH^dwe?t^&r9@tgggrv z-B|mYxYGMYRnT@a&*r9mrBB=XYtX*Tli&RU{nw+ zL|$Q(y(kK@hfX~2aLj*@lGKQ-4pILj_&f->WW#jd9W0^pW!`TlkH8LlD-u#e!)&RB z+dAl?j^*8f^L$_mTtauvZzwXLpfzNizUgU&1X*Z_qisQwv^B-V-3xV|^g-TAzPJ?O z$dQCCfHwIc_NQTGTb9tEDg39mPQYnCrjl)fo4J{$eA7;1W2D^@(`3*OC&Oo80|`z5 zbhy~a2_-oIx?T&rwBM57`+;Y{0r!;3Ht~R_=1@WtbW!9*F;PDAlo&S}Cqg!5m-MPs z;N4Z_!mwkOWD-ZntNjuaF&E6`o61uHngH9xrbpW*Wzjvk$92^A2t&0V~fWpO$Nc+ zp?7B=nbd5YwCgD z#o-L%lABciEVL-H-1m;oTbYCs&6+m;IE$G6i`?rv2j={XFP|~nMkXzJ`#S8T8bKRq z4zW^p@PURA?Sj1ZJiCCW>;5;H%w|lTcc1z;?b~;$H1FcLFtRyZov>=M1;tc8ChiCq z>BxZY7s`22v1JozY#k1*1h%Q9i%uAm@h7eyrjHaEj3-4VQo_U%1M>Q5=)Hv%GH7Z6 zS4DTjT?50kR4M~Z#;_z--c9bmBK8jee|nCQmjBZDSzcVWat z;aQE88cvb$V0(fjkp3MWE{&v=7N+QT{M| z9KRa-cegJBE5Br(NlurJVTJM4F+LP#5?EwJ-HX2wDs5PlRJ)c`pi2-b%;(iIN7WDM zm692bnKi(rk7-L;n)BJ-D-teBBo&u;#FR%gvKYD|UEQilFIj}hSd+55^8-R@;w#K+ zD^4Ukz!Uj%Oc;2)^gK3{dLkC(5F?pRShozSblGqMPFc$kty6-A3sg*7z z9By_A?y-vH+Z@jfVP3K1X)INDDbiKGcEjUq1pd+zJeaCL@>0=&Oc{5)`+i(%YqcLU zPZ>`?1sw??79@-XArT#d+n{T2wJD@##^%67P}+q{kw|fvTo*^Q3JkY6jLR&HT|b|Y z8~Mlx16bt>r6(4Kv;=8UJ8(%<}JH@y;}JK!_DT0XsgTD#Ud zy}3ADHZ=Y5YWg#M$=xUL%r=`|Ch5$M%FN#0+j--e17E%QR+5F_nWJ(&J*k=Fk(pEX zn3Khs^DDjIsF|-6A1+(#F4#VNSNV{!HFM?gVaMvjO~j+m!5@B>e^}4|@O$LZGJPYE zs}X1N!`;;MQEX$goi;#xc4<+FSX)fZBm7-hv?X?yeu71Ga^ZOqdmbUDs75^oG}0Th zFBS7*4NV!22W#xi+ma&xT>~=%mYxje_vmL$h~#kLd|;a!4s4O+jg>mVNVCFZ7esL# z@r-XQCXEdhTE8Vmq3 zwZ#yv$2WV?Z_W~ZLT4>?7I}fw+6nON*8vzhjfKXlh^?+yE!60^LN+gAH|~T5CVAr0 zumvU}J2~o!n1{p`3HbYC?4+4mLH(|Q2%R3Vt zb(_RRgTSRuGA}ntWfPvH+X_5_t`y$bRJvpkUg)5q6x3D<_Ok0eT@PW?!)G}oB*IM6 zc*f^|-aB@2WKmEG<&>031)gA+Nw}uQ5i0Gi{@~#(Shm?&9tOr0-hx5PnXl%gNu$iWL7m(zxqwJB(WI>~`t9Y=)-@!;m^%kv zINc*VvL=%%o;XnjGNT*P0K^4|&1{FUp#VWT-I^r^!Q#xy|ee4833n|Zs!G7o>7(IVCNZ<5)c|6`l#>l z-VevU%TDJq22F(Vm!yctKNc^JgW{EJKDR6n+o(V(ysFdrd6IL?EB~7}_g0yLV$ZVw zP~q+VU`!t^DA?%DEp5W6$XEg1bbVQj85_Y`UcX{`yoe~I+oTt`{E>A~NLaBR@EKo( z2*TXc)AXK4rb7{d8e4tm)0DW;@=<&wEG+KxqI2jL~vx6UOW~7sHjGebH~j?hk6u3w)<3!6FWyrT}sqGM(gfj;D;)- zpi#Q_%!XIY;*z88d&DOBq^9&w{5Pos>ey6r)Gg}Ndx?q#cBpJ*lVt}N_@EBIu zgv+{FGxCF%lWsq&01RzVDh*k4l$}w2^q$PmGGD&Zs5ugVXTELQTV_Y^KqJs#v%V6t zHU9cqJrSVcU`QY4UKt+GA!895d4-8utW4a}s!P}Kzt!r8X~(xF-!=24CN3Hyi8Z@j zNIwC>AvPv|__Lak)w35|SJ~CE>lyGv{3NJIT`Q|5e@m!)GZ*50>DB%23YQ#dA{TlM zRNPatLC`T%LYdB?_*ncdK#Y%xj!)y^P_Y&tR}m?*>q9Bgu#2ZueVRhTR0WmX@@g3I z$qtd9BkIc4A&A-ruXiu|D_Y}QKqe<0?Lz(OLUi)Ho$dE?%MJ!9I(<8DdTvf2w*rfQ zP6qWFZ`n?V^#q62PDiN(N1aZ`KM9OSoxZCScvpEk=_xQdb~-H~Fnw_P;fDVM^lYx5 ze~#m9A&P%N?QBVpf63`=g^GVA>TK;3-&*C_MkU|I*xAQde0LuY&OV#I?S-Ci&(!}t z{QzM<-&5lQW(eUMoqw6B0~h2F+mpaq7ly*nwHYx~n(;qTIBBgE@HV{rAK08a&BH=I z@&sWDB0S0vk?hXJO!QpQK?Xuqlx~{v1RKi1LNDZEA#5~~TW$XnmYPvxn19HW37>bg zB6%#F#NH{wv1{-|kLyY=hkxHta33br*CHE)_qD=M!KkfQ-)PKzp}|jDxR`)vHl7+o zT%G)dfxs)5=Hf@AT0Lz{Ci=EvIa+~`d5oO0vUnu;!&)1KtnF6;>m=1NYuwagtsEdwH}r%ykW2{od|X(S+8g%oSp zZs2zp4@lu<2&D6vm$ub+Z&&y9*e3?cttEG+(3gNl&CUHf*0U;BLuJFKO4OeF6FwaQ zC15xrop4lb({qSq2u3u8U&eR#6b;argJ?GH;*tlv2ea7q2^x$ zRL#ct@Wwl3%uhYcgDJs7n1xCgL%m8sd6hDE zO(R7W&KvY;y5u>W|ANvCHL4rhY~qZI}j9g z{BCXvJdTOemk)k~nNWqDlGB7S$L~4z{C$2Q8UREYSS8K|Bz~qy5{y0eQxJ<&IGZLr zZyR{ugZeu>cxk=zP5cH3R!UUNoasf@)6j{2!qij#?v^A1WWu0a;l&Ag3nj>rX=e+;U0MyQcsBI+w^^3@Qpq_^X+A$4^kR z>aD<+H6)c!uC{glz4@8BaQu(k1l&JAn1(h=Y(F*G(i1Z>6l(0wS?+Hu8|~7lrWdk! zj_~X3XzVePDJCY=2K$Q^J=4Qm#)W}MSK&-dd#ZyGkgR;T4-0b^DL#3WOR1M?dW548 z+^ngb2`UbOspOl%aT9?YkEvvtqZ}1ENMxL3b40eWDdY^88i1O!BFr6~na_1Ff*);$ zvIC^Sr=a05-TPXm_wEEG6@guhRujimgpMg(GDVd$6VCSphIewqzuD>YWxn3+hrp-a zz#revPJVn<`FH(w%%kouB=*Pt(|qU4elsEEt!m^wHKrNdxP?we@&kDsSRHb-m_liB z!Js;)VbWnl44<+)N*{o0212cxX#^-afQ9G@EcCyN*rvv_jtHTo!rnW^2zsdmkcJ{n z)~Y6vBm|}LVa;H?c)-HOkQa!q6djs;p-SlS2kM zAB2F5%MHzlBW5@8^ae-3+9mvA7=zH+St~ z&$0$_(AeHZb?pP?laFxLZ}R^wS}d1G8b!7^oP{ze}S^9Vj`8< z#%LmG?AW{u%&dg8kU%9gP%TQ?r^!T-wDIwx)(Q8BDNxYMK#dC7Fs2&n*_S+Owo3{h zsy2pkLo1Va08unLSDCY9j$pF~)OPw!ylMvNq>!?X?b;K~n45Qo(0fvhYM>@ZiYh|s zaIdlvUo|;`1_etg3OKrNYErvQ<9Iq}*iN0#Rgy)SrSqDz4#+s>tm zqlGen_zH2djqbXp$xYth7Jkp|-=#!$ zM?YCEG9^4ID>^N{5!_N1`F1C=C!oUamNmlgM%CU2kEg04(K(+taiIGSs5 zgq%dYNa&~73T+aaZH&`+LwwCKFGONpTwQJj;PI?LV$*w4?%_wjjgSr{x81&npF?i{ zKHLfos_EE@qEoI={ed&#kyFyAO_TC6hm{MjWX`)zJUh;MZvT3a@R{I0)5wOZUcRXtIzM`er^k%_x;?@doBO9;cLA7?OBiD!(SfHnnrP+4ZK$P z=kAyNX$YgdAk~L=SDaWN*{tB|iRwFw1%lhZ72GI&oGlOl%KXj|Lczxb70qTpVipRG zZHlx!eGV1gtP!9@7hAJ5f(0;fR(#%RqeCK`!VcSE_&{YUy&<|Cl~4k2^TD!%Zz4ow zO_(Q!MT=(55E7*W0-^thuJ;UUVvXK@(@7ve2rV>CLJPekC~6WyC-e?N=tV$^ARuTG zLY3Y`q&E=(gCc^Wo8CdXsBAY~L{vaUtQ`LDdCzs;59fTI>v}%SJTuRld)@2)h0{f) zY|4;x(DW-k-TI&@h<>XN)DBLEx`74qgL45YG<^__sqo#3q~qI~&-+l5B01BV747VP z8e79LM3j+0Dh|U(RR_%(W^NO$0HLq}15jxgUJNdTF&8Z2Z$rvlu(slF@IhB~+(Fpo z)RO0NSg*rK4vQuLzqiap>sy=l&H%7bj&|-5Uuz1djm=bThp{S`Dua8CRLmaq8}fXT z9Rnuhd#&;z1}eeohli524Z9<*$%FdPT~nYG7S$ltpZ+$27q&>G77^*3wA-noio4CI zbw4~NW(1ZuW10jZav$GNSP?3T$dJlvTwf*Hfq^Kb4bHr>H>yOHKLdgVSP!Fw*mMK5 zbfxijE=o<~^*QfqIo{l5!;wnFU6g7SQU_y#x!sp1HFqypkuOnImI>BU>`CI61Be}W zTe#U5r8jWIV`({Wte~pFK+sr35nIAf(8S$kaq*Z(0??o2746KPFJzGQW$gozY2SnDUPqT;s4r%}sv%N9Fa-t!w*!MXJM%<2e_k}2V z%i5;1auWN8QbF^#?AmE=!@YGK^0k7czzd3Pp3b%x&wBs7 zbn^Y~Nv+_$^N*k3A>yp>Iw2piimKUIC}GC<7*?YicdxN(1q9cuMMcR#v^~5 zy2-%Zzn90XsH=Gsst zGFF~ujdQ!c-7-^+hscnZdqv_44FVYqmnHitu9BK2w~y&GSY%M|ve>HHdCRzMDh)8w zw5e6WbM@>m=cz@-ce;_2SM45(F0>iGJNqRzVqKE{Cg9CG691D(V@1ts{<6;V3Qwl9 z2E}SlD!n(UQJN`uu33M}@4b2Cli8p%ZFlsQw(COT=IYOB-89YIwtx7VUKy&@`?YtzpU zYJR+Yod7_+d24v|6?nFTc>C^Ds3K(N@hnx7M?L%`wo6T{*LQY9Sv9h+dg;baolH!{@jGU}~~fp~X- z?z>n=^buzc-AS}o$qU}one1cTX(-N>qS-+XeZ=G}9WGkWwYkKpS}o?F09qD!=NkHO zxbw@~mns#<9PgjgIR_FsDm|%&$u%`MPX4vm;sbA!nAV{#XKjTndp{xQf+d)BoEw`6 zD+M{E?tF)ke9}>)l?TiM&vne5KW4Ij8#QP>>d*c;a+^%AZ)=HC(;m`oDz?tgWjQXD zuKXDjp#XYW1B2o7`pboZX+6ePz?tQ_7FM^74#dQX4%UGN-dcb#ShY?6xkBhDq7eYH zXs}dR-hI;JhdqDg8`oeuCWHU)zssiV1+T6mul|K#L63LgCx6MEoV2Di3sBHY{Led& zX1^L3_=?Qw1)hZYBpC!Oe}|@gNg6=g&A2LZ{IbpwZXNt})*$Y;(D_1f^8z4g1uM3> z{F&MxD`yx-f?aK90gDW5-g8_p7`QG#Is0v}CIcW0A!bYU$AvNe3>XVMGtJCNiKPvN zO)XzUa%3N-x;WuDP8+0fr#WWODFWR>Zx_*F{iU^>p%ef(n0~d3Zb0`6jkmd0w|p&A z9M%N5IAzRit5QD3HN5)w9DDw4vq^^CxObh=8}1uqcsT}H$z+)&L%Lf#2A-|oh~6=q zd&YOA3D*rbe-T@8+63N9FejM<1X*L~(h6ELKp2yPG9C#jAhk3k*B78IrH`tyc~)j~ zi)VW%&!k7YKCUX4I6tiu8Ilx3NVK(!`7sw3>IFIOZv+$P#55@ z3t7YhJ1Jv%pO)6lH>_HdqL&8cwWdP0rY*H*B`+R6t2IAiX+Bv?1zA$x)>>>@SbVCr z9JR3gTWi&5VZ~Eton>KtqRz%;-B`Kqc*oeBtFtq-u(PPMm$$HYuX7Nxa0sn){7H4Z zR_FAV>XcRI+-qqj&-y*ZYgAt6I+@u{GJO0@`occ7Lwc%1je9@yCit7sED=zRbzCX+ zo;f?(iQwm_;M!Zo_@B8tv1|{bkTCJu3%`?ft830Ec`B_Muu{h;?MD>$+>|Zr2Bx7W zWuwO5#lB4S)vG8-K{zS-H^O%z37(rn?MX7bYg3(3CW4R%4$8Q-iT7!VM{D&&DN%tsbj2UZ25>;NnhlVrR&jm_R8cp{a`gCWx(WWrgC60;!p)@T0;@=zlF=LClf!FeiVvhUEel zw7~Q|E5HzoV2Mgq+wu_w#y8y{Hl&dToTm|frN;M1T^w=djWi*CJ;}Vyn!h%esLH_n zHm;8s>SY6uEr{vYoHatb&G}gK;lPDhH`20Tv#P00aX=igEP5%uay03s{jFf^dw-GY z+d=)DK8zCP`_ne4H&CR zeBW+P^rP$@M6eLePn?2I{CUNxP88rpJv$PmCqNHxh75f12-@V9f(ol*CEuY*6HFiu zwj`mfCj%3id|)dDvy6+Fg!(*y`IsKsoOKlFAwbtm0%%EpNI5LhhH|8eHxQS~xn&5J zQjGk?0TPM+%)&rqufK)ZErPw#^Q7KCT!ZS@~r&oI~s$@ zjGOB}__)Eg7!cV>4-gs(Q@?1=4j@rNQmyJAZHfb>WQEoQE9TVmai#^Dbxn zsQY9}{}5i(KweT5DPb)=2_~0@94D1eDZ`F{HOAqL+#M@0kI9S!+DnZ{7y0 zqd?wUQ>Tw#qaEAukO@N%XBy`x8|;iJ;#Jl=N(Paqnds9Jz)vJX*zZkgtkuxLK=+To z2JhQ910W4J_V~TxdX(FRIhj|2?(YR}AIy6oX4jaMU(*99kq{lmvK@RN1YHa*awj(h zeGj2={6uhtLdPg>)Et%5f+7JDI5%21{2b>i`7k8UQ1~i9V>^_j`ffD0`DZlc*I)^c zJdF2KBCkyTL@TMF@CYcDlk{BeenrzKl+DVqb?=60GsP<8pyCzE4OqyR-{$!;|AYET2T^STAwFtClbh7c2*(8)1cE6unYvimMGv`4`jfm9 zs@0MWycwE7<*cr0J8ci(<=fxrm+{>DBy&>WP5%N7FO-b?*%+EIN5Lqta(^r!+BRKT zUj6gwBCwmt&!cF?JZ{+sCR@Skjk_XaC-2?5ITE}T*VE61Tt+Ak>~khn*v-Ug8cA;l zM!nh+5bmFdNcJyIKX7-7H0N+b-bK7kVHyGmHfdP&s!~EEuDn10mck_gBLAFOcz@ZA zCBM_R`_b$pQZg$STB)(}+CPAXQFkFK{Md81O7^8C`w_pyCmAN(f(13eE)G{?uCF3c zt6Sy$2*M6*7z^|P7Rs0;xec3N9)2DXN`ktngGZRZTTWe5RUoII6Z|53Dn-hDFwDn^ z84M6p?D5YVlC4&cMS9`XHG_u@MREov?9CMWs=1~k$f;kHtlvhxbx|oQ)BXpv%Y z^;p$yJ+iHO=X$xmeab%IM-`t~q2ts}$ltUazyVcZ#J4uTqG|1tyXJt?mRsA%?U<-~ z_K_1}1Cen7QaOdG+VOsdxFAp}p;E{YWxX^hCH-+(eB^V(qWFCWoZ@1Ju8e*Z7-m)x z@W6JwMt8o#;d>~{XU#ZRbL@W6$ewfAnik5FqYQo07jr>VyMcV;`TusdJ1OWT$XaQCa5 z0^E@>&7PrFOJG6IRaujbYHA+e9mdd=d#{}518U2sGf!J^`gkIFG&}yLQV%c3wEl6f zoUcp!Om!~rNSCFi-|x7=Yw7a5BjY9Y#*2>3JLZ}Hb!1&K&-&bv&1;cy)RA-1C5QK@ zGnbc|eX=v}yFs2xXa1T&{`t;=cOJQxorPaw3OzcDz_GTWoj2EFimrDSJDL<^|0uF_ zee|gA*8SM8kl3SP>9~iTr6~g!ip<@WC*1w)%FhT2r2>UILJ0prA>GR3khmcV{n>>` zc!RFLa@-TOdJbI~+rz+d^Lh`b`be`HzqemJUVNke;^0Q4U5F&{*7(sZhl7+!7aP3; z2kLKxX4HLYBCa<@_6`sap&@oAk)h@-XY6;M4DkDzuvPrbl--`{F6Da#&ieRo@Vo~u znU41K|0ur{J9%eu{vELCPFyLeO=B)cul~`msG_&;OtxgBzrMQ;W8YNta9@h^5IEX@ z)qN(Meaa2_t8np5a=XvC+~9cGt&>SfDW5odQwhn3CTZ$DX^nT%TeMoA2V@ALGhZKs z0tSvhzga?*?7sv}M}>OY4kspXN;+`(Qln&O7_Ud5?L!LPIeI(SxS&2h3zTQy|Ct%d zI{$efyr{oBd#l{ycf@=7JL#n3ny*~`i&*ZHdtFw_dz=|LpF1;9!pGV#_fQS~cUU|Z zmo($gqYI(SPUXzON#WnYQb0i;L!s19Gu|8p8-e*+2FXJ*!(5Q76yO4%&4Nk?Sydk4 zkkC7JR`}(+Dw%D&9r2g*DP=5xVTD9p(dmx5b+t};4c&a>>Bi=0WoyCr!+(z&H$8V| zA5^rSxbxhdKgCmxUq_)h`fD5W(#zG*c2UUVbpOYH9bTk=0Jnb#OH;b}lLHfW`l-#n zVlK3+T@LWeVA8R5HDmS%H$mzP&algZEREPzF4{hv^_S)Im(LN9P zUqj`kylEVI*!^;%Y-kUB_OlnTJLYYa)A=^#{$AF!KK4la={fZ4%Mhe05rx9D01Q3^ zr;MF(H;4f;4-;?$4gwj%CY&Rffnn^boO-Vi5FHm`N`Y2?i-t zL*S?lh;hYv22AjDL4b9QQLc>rlY;k_|J!)FMNe?NznRw0eWb7eB!*Lvj5;h#6)MTj z?SS|dFnv|K`kix3EEy*erGduSF?ezi=#bUDDShE7d3RgMSQ;|LPerfN#vm%m8cCL_ zz+166uVjD5{t_FnM6NQCf7sL04aEF&-XPyEQPo7`jjzL$5_og`Mz`!zZ>V_N!N(=y z*v`i4OGTGQ2o7Oo!b-*qR1cz-TT%5p*YK-~BR6+dmS3@Rx1CkTx=yS-qO-}Zr>Hx5 zS)n6%v1K=o%oW60lR@9?2FpX*SzBp%(4hB-9%#`vwYz7lapwWZPJZ~|?fo~G2$P}J zFV2B5!@J6rXrC!2aki6#!gm5)nGX<^`=Tc#?ZX)w<2dz_t!Z`@h#j$u-p^Ywmh7ptNM@tQajjx-^!v? z_qMe8NdYKH2Z{kK#n5zk!;=y^7NnKjJ0g?Z`({d(%x!RaN)Sr`Ly9fXSw^ZNUlm5> z`XcjGlf)Z%YPsJk+~8Jrg04yCazaeGRXc{6H$KDRfDAkSbk!=sNm?P-%SI{Qr~Ca* zRGb~ZXq7n*|I^M6%xA~0cE0%R(aQr&UW5y1=klbLHhxzf=Tis`N|GrVUVSRqw4>4- zVfkCmKv^*$6EL#;1|Z|k)w|%}cKt|kaXFFCB4!9%SIyY~T^Ao z0bH2ty^I^#f9-}rar~zl>3Wg&eVRsKV%&dq+@Q-gXCKBOKw9$qa_K9V*Dvek3Z9<* zM?KzaLH9jp9OHQ#GbpTz&1T=jdSpV=)_<~Z=W+e>VNDPWc<;ghwqHMOg}r#@8)6qo zs(Ii)*7$bJx{uEz04je?{5h6`vBG80;+nyn=fs*z)hen{dnG6W(@A(+3{@qn${g%#Jdl7`)kpV@|oX`g7Oa+mK56%q{|+YE5itevR9Fc?#vK(wp^jc`?~*6^{Xu={;PkvZE_ z?NZ$`C{*G@r{9MSBxd~jpeIiNj!cioP0Klnp<#bU=F$Dj@<+5P1o+2{yHin_%npo$p@tB4Fc1RK zc~!8>RFUe+M@gkL2O0`A=MI3WN%iRK3`?!XBVhk{(z!9eM-bgKv-cEUN8r|CNEnPE zlS+#FN51bOtk@hk#myXYUUJ{9Nmk#7B7CkM#7QYJ%{n4})IqEm>Rl(_qYY4D1_0@_Lx zkV)4Vc9u=&@*O)Ww_|NeQU`)Q!s+it1$Dq&4v9DvJ3%rNq}eg9Uiq5 zHitxga9t5~?BvY5r~e8x@C2Q$G#({~(g8nPxOoPtxdL5U|KQ1Y+i5_#s5LW65x9N2 z0GP@Y-Am=rI#<;?1cRO*31-?~Oi7#yDQc_J`WR?^`}Krj5dj?5>}N0L`f9SM{n4Y3 zA;*}hrB6kVpMCpyi6ORh;=M!1fYzt*+}my&GDRI@QJ*5K#4fzIcuAP3`xMoB`@+Z2 zQ|${IpRV+Xx$k8O=e(8v96Np6{Wvxt$0`tWbw$kM$E5Jn&AQJCd$&FQlrKF0_3iU@ zp!gB3`M|Los=dqLE0qMv7WZ&Rhb0RCrXehgd%tFeC8?Eqaz}pe6+75XA;mB8q!jl{ zYqtg)#d`_fFCIwEWM6#DPU7fpAJA&w%Zz-ythXF>a&H)%#Sr(w@xFZ4#c!(eJg(4v zs`$RL=zg{Z3M8Y@B<)qnYZE8q2-h1XD0ItUqrUly$Li(`3-nEyFL_AG{*Z6SaH@^m zv`1d%HEJ7QM^_&3BlW_F@!Fi~g(3nO$$5ZZ<}xRs&D1`57UC(e@0fa9Mf*mn@Iv)z zzx%2C=9aHvtoA5OSC}IE2rR_;I(Z^q%|lEMt`=995L^8XJcX7M^2~9 z-aq;*w768L0*7)?rz*U-mgzRUD0LvAVa#u218Dk&fI%ff;8y09rMz#%bo!!;i2i3i z&b%44iwcE{ii=xS;e~b`;TGL=h`H+QX8r!X>u3gQUA495+-T$N>Py$&v{>GAi?(i< zEkG?_B^>;?NOmWpm~qWmudPRMA8%*1Y~f-qm<$#0GbbTD0Zfx&<^=~;luYVf?7K0k zA2#h(>IEsBjxB9UA>?Nf*LdBj#V#ayRFYyT?yB8w>6V`|e2JR~uCBZGLk$&X@{E;{0_8DN z+L1DIdO^X$gzFKeNiT^~oKHvj&9fbf@+!Kp=`TQQ^9APj5-EYcP7<4eyaf&C%alJ} zKI%L8fs%rLV5?zfcWpR7%zJr(e?w@_B(30@AKU&a8PBu)!LUKa;70-v~p=Zx^a3sVUSGmu)i zv{hzyr?;E!<71C?}bZ40@sW@23>MWC$nciGqKm~eGRY)H= z%37^^;6t&Jx=bHgwFXo-p`p0UPr_@PdJ~YtHAkW#2v$YYf~HyBsuR4XBbs?CUf+`Q z-OujsEh1AaT#~S8a1rh!^&6z-jt7|!7&c8&v?0jQH6cXp=dDC%a^FtIqKWW&l%P`6Fmgn;Y4u)~ zlt~dqkDmIWt-+~=*Iayy})mU6MkdS_2~RZrzfW@CVB!gP)lo8y;!v z>TXC?DEPP#mEMrWH`tIrLSs4ej$hDOC%Y!9295+?(sJDJu7C4BJp&I$8rf>>Uw z2DC(QB5cB{D*+g~S`n0nsYK#w5Syf8mO*}f1d&DiNtg*NqF*qlCJa*t*W3_b9-}&pMXUF9eRb;AOZO)9QO|T4CPDZ$Aq#ggzHD zNDf0w3Gqm!%N%qwFP03R*P{lF=c>9|Tr5ZqBz&@tScCKqnhXz`v+0=d_47aPNO&8~ z%KKM#^HOYWr1WbQk1+3KL-%CDHq?(JLD=1X87A4-b%+f_uOqNFZorhdm*Ng8d+T*> zcJjXy150}Q$*)6@I1WQ!fpbk7gl=W28yW;qo3^#Obmd1`zZu<&=#4CC*&#kcKj7^A z@)@28T$jf4ov|xyd`#E2d}<2k{T)coyF_e$EaZ43-(N>BG432flB;^F<4y>DPhr6S z`+DuGDWimrt%Pm=YYl_4I4$*kBZBDG_22s39 zJ2$F^GfxE`Sp}&6;|uxSn-C))RT?O*xTe)I#OuEfafkq`qQIq}6}a(s-zeM0`_HzxVmboUo%!2vA45A64^RDS>pZr8-ih#$ zh^MZMJx7`3rq|}4kjtC#%3BUpLa75(P4e~9^Y!G6f%XN)BLz;r<%gDjoV|s5GDYGw zMWKk*%V{?S@Wu4^H*IX*j2cZ>>btspx)rRSdO3}=%@5j=X32`)d2WL5AeP2~IOYIn zSEA%fsW;Wz6qP?#ae60=62ArU*4b^-14iqMB0bnxM1ToC7*^z4?S}^y;|4>gLbDvlZT;hULjk?b~cD39{j;1gfNK1q=y6-0>bz{BCfY8rJC2 zk7%6+`MOCf{f=($QDdY0L4OY+>4$w&oHtFQ?w+JZ>lb&gj{;`ne5*%gs%1uB%t=l9 z?WPm)FQYTP)Oh5c$}b+Q40&B_8r{yG+TQ6fa{&aVq6anIOfh%3t}1z7w&hx8W^{kr zzW3F%{Wm8&t2r8Wk3D!#;wT^t4dV*lU1>18b~gQ52v8&w0I&~gbcHHRE$p|sKG0>4QQQSOym@yxd z36{%zb(pz=@pKOccm)rx9%k(w(k^EV#Vcn2Im`}cbuaAPD++EcMdpP2jFsR=iJ^#? z#1}lVP)tlt$1F?4x&Jvv3Z^@+S!>FdaQV;I9~*s3j1Chkv=8lO**v} zxHmJ6{pe_Vr8LxQGn&;%Gl>%hfmq9;BQ@{cboV$LZx(_I!J*PAOp1Q*(h>QV*?hWf zGN_nDzC{|pmGI$Z!FTy&ZqtF#*1V6)o9h71Z2*KSVx74}Uy$u+KKERStM6;ctJo09 zVO&v|$6_Xq-VpLj+endkRY;yNz6u?NuFiQw90IOGPFLiDF5O@n=aX+sL=e7yZ)|WT z$n5QQUo3^DRmUoSZdDsO8!LBBs=8EL}iY9+GR=M2);8?x;K2KWx+Hg<>_;X1C;z-T-9lf<|QqeL# z5WMpwv_r_S!N|OUsFmD$eCiZuf=-2I$FnU1O|IC-M5Nkjv^`T^j~w#9?G&&{Ve&mO!8xSSTx4Bbjs{*JUfShP?s zGi>qXx$^~b|J$VO+t;4}pS5K0b%5J#eKqax(tnTNADX#za)DQ2x9U%cBV?_Q)VKx;%@By|ekiAZ&ooPTgotQ=oFkpmLOb91n`j}~_&d6u~~C~g;d-xSH` z75G6FvG$rwNj)-wMSrp6SExMA!Y5XHE!7;LPETSvzmBLlbn7*KC5+Ov-u8RwOnVGV z;j~5j1-(!o#2#jELQwM;ucA0yJ`P-WqsHsm6Vh?4>HDdAi1GrYK@qmU(yeJpnfVx2 zR)fcOM@TRSdI0_cs%Lgxv58ibfnj-$OE1Ec5j^bY{$21}wNhVu4gWZRVg<%+r6)In z1h4xmJm(Y|AQ#%9eGo%F5cPBX-sg_MWfQelzbr8dG3V#kF=KehH%eK>4-FrRLPs4;if_9cBW7haOGG_Z{J^kqhy-qO-3P{O~nYb59D!*-+Bk z0GC&JHjJ(aT6X!U#vo}9*~&l&%1e<3<3zOG`h7PZY1O>S-UOyCHcZyj$L#Ks$;cY% zK?=@L_{76C|HXtQN&Tg(YQ$YH)zz~Rrj2-Wb?9y4MG)3`a`z1vb3Vm;_2nKx^RMq& zus)4)dvAm41X@U_SLOMuC3B)h^_g)=MDD@y^Itbf{o2(7)4K ziMV&R?(!axmlu9i@kqbf2BX@Yi0_oBue=&mHa@W_!wG(06hZ znK$O0BwK% zt_Ou-x!?kyUl|~?)^5D@QDHtj06j$cdVKcYlz#Sly~5B`YDiH!(xXZF`x>X7bh6j* zm*3;F0rUBJuWjd6Y}bzpRN~ak(*B;iBY7T5_5Z1{aP+YJxEV9>ne=op5UqJH=D~cRp7!yPp9hkB+3B|#41H#ERF(D4?XF!tNS>1l?-L+xL76sFKRaqw0VC&aSB6v0!h%B%<8o`Q@W62dahL5;dfeY>x-_k-XiEjbS3kXph+A=?N_6J7xvfufN<&kHxqV=zuU=orUKczxH)r^u>E9K2YvF_eeFC zZ4OeNe**2Ki{j#eBc}YRuThVJ_EhAB&#g=Y$v!xDxEsX^ zU;xSN9sq7AEgmf=#v^(RJcWMS5&4tid^{DmfaejS|#)L zS~egG96*g6n1880s|K9hke+ylLY#2QiS5HTa7F1Y2_W(`90&xm!%?9TogDw!S(mdV z1a%B@pzaBL0t5OemNSNjY@CMj)KKFif}B!2Z|8flVwj?P1_hYy>Z?*_rHa9LAynIMR#wUo0Y9k=G>O@1UStg`|uxa~7tgfX#qPQP0Z zZ9@45Ky*;d7+It#{bo+}tC=it&vtE7TLeK=|2b24E-?NX*8Nr@@P>6T-}pfu11{fi z^v1p4FWtLiHBZYed`NH;cy9VV|G&pxSfYba=Aa!A)`i!a;#3i-FDfug1;X5gXwxjz zeNQ<@2(imj$4r`1PnwD@oG& zX?j;->FRV8e zz7mC4idy#-isRjHyDj~eSa80SISsJ`bWv)R5*e>soTMB?di(tN7Nap?xd!}VRy{W{ zUMPzkupOnfAFbvg02CCzDzVouI9p&KVjz4?hfJn31`y=R$8Y-?3o%EAqY$XY7MELU zD-M=-JKYK{^VwDBU$7uOapc%HlO)Rh%a0~vH=LBXk{bEE%ig-6$H2et<}-P(bo&9~ zXRqJNbq7w1H%VyZm3Xmbreyiv;QII4v)_R+*H7zT=Qww0^TMk=W-a@R%x%wKMez>` zr0+*UR?0r-**}7S?zjz-EIcb`Tej9o41uP~OEyAu{+MBAwM2QIH*qI3mbSJX7t!ZIK7O#l&a68zU%h<64OC`?Sv`G*>Q!wr(h$HDAZPTxyDbGh;o49gjG)Gv8r?y%o|FrY^;4Cg~7 z(m2Dr)pfSRv*YI^VJs_#%t3gLT!Ey-N8@42YD0#OC|&ZuhGApVh`fTPT4|NE5%cZb z+>)JI+4G1|tMrJ1T5~B`v$RpW#)!hE;5r4B*ipyPh@!TpI;Bf#X372PH@kM~RIVe& zY3IUk_A1t^Wv7k%2;~=#2G?s;ASMD_@@~yE)oa~Pn+Pt+DS5q9f9fBEMM#83>AK<_ z-4|(N;nk64JHdC(sNJ2sG8$R_wdtK|+AQ(vc4Wox9e>2y`xkW1%ay+&1QKuh6f1AG zk~5@1|Kw})Wb)-|f#wD!k?rCC87a?cYcM*`X=5s?dBl6($3jmAGgHubxh@P6pn~rx zb-#Q$M`26YYzWFAq%w{}3>*R7Q*saH1a#V4$IzOF)$y+i5)bmk5R&YA$a8FVTAMIt z4%@5S*yBxc?&0DB%|V17<$HguMxpMS#qUokt0cXT2wo9GvPn+X{lwqsV%ZMeZ+MKc zJn(1w%bbubMF#;lQ;`Uw>=%qF+f>KWI3=MGZyWy zUHfBUnee4VG3ekF?l1`Aub9Qo-7zEda#sSbLy z8r^y-+WMW)l4zMq?OlXmqYqG=Xx|dEogHt8&6#&HQdrs7GWjYRY zPOl&$mibUT98MP)*Rh{VUh#H))CwnlOsj6b_rm9wvW@&#>ysy`6_x5&Kc4~WW$9CB}} zRKU1PvJ7DUOBK>7ls`aVcMtOxD&;%Gge)_a9=HJV_*Ja!I;sTzF#`PKFW})V%z6y0 z9DsfB7d9bERwP4XlKBi%Szy_7&fcQPNZ7t0%WMD@^_b;sONgF^Pyx}TjwsB52ys)a z5hvJ%<_}@U5{FeV;e_%pI*lNH&nUhNH~H$MreYOBAU?!Es-xEv%=00aT;7E$O^F55yIP&c4P;zGA2>tw>A^ixPp%1Ac*z zdrY~8cuLh}VGYzwgi=6V;`^5hIWPv5l;$^#dNC*wbo1n^trP%X0Uyb`lO2y7_0R^%jPC;JK_rz-{Q&^t%U7EF|$a{8Z$)DpjF(kqDm z`{KKMsFq`sJ=RELV}VMhKH4XuV#YN>pG;5X2f zBBh?fU=x5ZI8~gXJr&DWi7)XRJYlh)?yzDfyX(UmrbAcM(hpEbIe$_y^cdzoA(Zz= zTe-crFeW1T1ix3HddO2mO2WR7Fyor-p2rR0U?d~O%_J9#LrbY0300<`uImVNcxIcK zq>`kWpPgJa_H-o4R~P&gR9is;o$}MVC=>Q|vDFjp(;3~k^m}Q1m1wb!4o~0Wn^f!A zyEsLROf(e*N*~l_A*5~!^0y}Ca+QcZ*Rq=!DY?u*eZHGhyyuzyQtzJ;iBmPF^k@A} z@}VVrTupV$A8J)Ji)2MtiI4AzquRu0Ndoi08VA1oAFC3}xD#aJiA~RwhQMN9wah)W zli$KCe(Wj!UdeHkkp|mfIr6Z>1K5II?Id~J1IG(lxp=XCjM!z6xvZc93Xijbm3Z-2 zC*$+(;5S|=sGubsNRoIH(nA}C?0wLQT&!7==YPz*X|SXGl;IdSqroBhT3d>2Tps_$ zRp&+<_f{j6t&Oz5mDGGLKwLiVwR!_Lr;?u#lrQJXqr7?xbd(S(JU$gD<0*i{!WJWs zt&yT7+j9AN4a?yM-kntqWB@0dfZDZ3<^r~FskfByLy81HZfn@lPpGHnhT&y3S1U6R za`CMcA$E}YX-zrL6BZl+#{R;iqe|ugS%0SJSJ9JYd5vdVA=-j~Z2T$ER{aL)Y+Rzk zlLzrgT+?-frtwh#<)y6yC~K4Kg~?U^Fr)k#t@5Q8_RXtesZ~W<^a?;y72>UW*nmbn zROSAnTBxr!ej4?@PfeLq9j~u0lc=8jPF=p{=*(k=$Ji?;=e;7EY7J+88kwf^p--!f zta)w}f4xpKVouYNU(0r_x~J!YmlZANL699AXxWf=a{Am21Dsf-Gv5;l)R!=|5pPgF0n4U=Zr7=Y{$Yw zdw)HH2MU8<%Kq6pJ=J*jsbiqszSxbcc*#T;In(c5y*(VL0xJvdh9J~(!5*=N|H2j`D6pbUVZa8#_x>R?!)_Q9nd`$phi*D_7PyUMkMOusq(8OW}QGrBG_rSEQ!z3i_?}M zZHn>H*I6f7#n^uN3R06-HbD_SO9O0kSIep};qLC0D^m9K@Y)#K+<*4h1DrWpgyO#>@< zYuB9t59A=%T%D)+pl|SCuiBu0)8Iw7!3*Pqmykn(8-wBILs9Wok-a{@Ng2aw!4}M>;mn=kp8nx%#gTkBvt09$n;9c_eMWALkCZK$+*Ty} zjzE1Q%KpoR&igUB*V2Pkol_Q$?vx|P%8{cuN|YB0gwh9eMxokk1d56vNGxo1FMe8h zY#@02;W()oEheH$&`)Q|G{CH9Lu6T!AG0+YPEyoKfbSN%Nf9#2oeGoF(_X zwbHz8^Q<5d_yc)9A>2mXbz=U)$9WI#1y7{~Z|Z_?$bx_7LSXa4#fgQGj|-Q$Uxq8a zjHJGd3VC@Y^JQ%F%c~PF6F$E5FPr~ASy2DKu$lkg3si^;017ZYMi`j^%HT*8v63GI zg`%;vFwZ^~2M!;93?1vgAt>or8W1iyn1$6!UMD<|8p%INt*5+i-54%Zz0g=NvM)VR ztQ|Qy=WM${W&%N=|Cdg60eJeDa>M_>DL3NAVORze{{Kn2>DU$jKPfl1jcvw6-gIW; zFrn7UbNOcAd^u!yDy4@EJ8_IeioWYpdJc3!{VSkKN~8?(4eN5)^Uk7_kq4Xce#Z&D z(bA4B7|oe&^98BthI2+?os;aLaozGc;|phem=4G@(c9#Q0cTsp{~yYYyE(CRv4JFj zmzSTSs@x+@CfLXLijrUn?zy#e>V5Cz-l>9&fre$FQyMQ4P=}<4_Tl$WT)@kGvM}&! zS5MOtYBkEcoZIJPj}K$@-8gx~i;Zdh@n!3OC^sj( z*M`6vPIV|LV=H(bB^I7u|FV1B!X8%Fz?xQT!z-jg*S%P6Cs5JptYJ%Pe;w zOV$c_8Zte1eHm#t!N;F;c#P~QBUq&?z@}DjsPRzhh^lU1hKb0noI2vZ#9hZ6eIB3n zEE8opD-^Zp<=e8D|DoK(KhUfpKI`6uoO-s!q@rBi`Z85}RcWuTmq5Ey<$J%bW)fzo z`aCtc(C%f*F?w}W_+RN-GjVX4VUKRAj(*0eT#+O6q-L)bY+7RZE82+4)hZ(%4lIbs zjB14t$8^Ww{3-Bv!*CBkB9b4-t`5Y#qekQ+)XEw1SoRs^*5iRuCra;)u-;cDqH0J(nZeBW}> zzvBO<+}!`_PGZ0+O&x%$yYoKaZyfJOR=d_2I_Dr$&ZG(2{@4S(G#gMa3}5x$;L8)Iu9a+MJ?3DIj?rOCrZ#4r;oi$ zFM-`*Sv*k1wVP5)@?HFWQ5<1c-WneCUIAQt;p{)e9#a0b(jf6Wtb3@?YDz{tL zBMnE5<-mNBv*Xs(VB*!*qfD3eSNwFt6QrU`jhHR;w$68Xm!70&I|a1UEN>k24e<_tGqGrZU6_6o9phnT8{YQv-o z^jFoL1%-wB#6$n<)n`TaujXd&6o3OSbF+%~GF*+OTN7U9x>=Dk7K>?8# zIhp*s{*{sa=1EAib$r^av9V!ZvhZw`@|BS>cXw6_9bZ$#@=OI_LHrD`J2=VzUQSZ3 z9~HTvTyH|Xpvq?CO%1B=5^I?($;{W_8Vnev&N60{Y!yJ#K`R*-v1E=fqE+JDb{r8_ zcWy{s7P?hhb!2hs@@J2KU03`*p}OaxG!eGivhI`4mg{o1Ia|l^o%j1KuJlG;+>f^% z*^ag3yOozvvE_c_tNIK;XN?my4eUdvTVa$narCh|6@Sy&l7k0o0S$DEf6(f9JAe7; zj`6kv1lC)dU;8wQL-4HNMDo|(YHmi-rNiR3o3Q0uc<_ck3YcZ7R|P<(B}rXww1u%! zz<5rk?(@~mp<)|x-bT8>O()DfaJ7SDk%IoIB8Le z5l_Cyz0&9?eCB>@-h5L(=|ky)D7`(e*&`d3!>dfx84NKOk^poOk0EtiT!qik}onT>W)f;Co-JiLd^$mUJ+2_p9|7>0S z?`%1`Bf1~bt8Ro0Q8cA^_TD;yNv1(HFit$lY?ho`-`k&uL&WE^Bn%mdQJlZlKgCGK zRVSL{vVikWdu5!vKmkfN>l|&1Y*pzAcM`!NRX>w^IdB42_mml$$ijaza$ft09N|yM z!@(U$KeZRENypO<%@fDpo%{7eO22)WKhz}GvA?$x|B5W(^^RdQdP*%h6}tL%q}*_5 zbviZe^8CT?cNSNF&I%wj8;q#ijIbwj4Hl0o42~%`96#ocDK}02)DJFielB!OK5Dr# z@xlGq&zIdi?d%llj+fZ4#bJx~2RA2n{LcJ(HI>!gc8B^g$o1Fj#mV;e#}gkzul{qE(|@kr#a6dAvx2WLp1B zU+>R#egA{!^}L=xY>&tNcDn(84PW{9J$JJ6lh)*~iO7Hd(Kx#{O)nfxpEMWg7rM3` zUjAaW!2sdZzcW1e-wTWX4q7L>cJDllmRzd)rrz0rPSl2YFxr9K62&XB->-d*j0K z(cGzaefWlS^%d#4x^ zS%baPBNxr)2nilylXL@c$cKB*f$N7z?>EBP5iy=}G19{%*?D&P&1m>?BnI;U<--y@ z1UltI#tTviIEs-Y#Uz|!mP@f{rC7~VtPd$Rg0XhESbN9V%i*zXxckAFXmRYFB21(j z;y$M%P}mJ9I)5)X2gaFue|#B)Y>gSWfhgq0-NM}o@FDLFMR6h?@RMTiAI6gesWCVz z#gQ5pPNn8j6A{sCcM#min=#`|#3?#7c!SE>8ashuJ1lyTuODR_e|-VLV40G+XcL=oAjIq7UC z#gnv*kYg-Z+y)eky&Inv!$L}S&4pb~gOM5OncgYEo8jjKv#1*^MmMv}v=iS`!&9(O z%pOpk0q1|qPIk+16Uz3`&h~W5uFnO=qtdA@+2i%G9EZT%;q2fR*6*z(Klz-fWjIxU z{Y@^c7?T+s&tAhsSlrF=%gc$Z%Hl@E2bqTz+uXY$l$W8Mm*td~{feZ>>YhkiW)2-841G>C9)j}r}% zPdo8Vu`ke&M>LdhF}F@JuX8bfM6qCgv2c4adZAeCs2Fpi`qU|rb}o^PD3Q-EQD`qw zTqrqnRDu;QRn;j~cP`b8D8&hv0`XMc{8Ig+QhZ|ZS>ZAx=Q5LsGPC?Li}o_Bg)-}- zGNewKjZV3}bNS_na>x8~=k{`!g>rCvsoi$@iOJJJxWY4{!Y9ANx4pt|p(5a@f+$=W zbRzE*E|#-_Ig)^(?Uhm0C8rrMTL8?1R(a2v9;Z``qrv>@>B+|JjL|5t%@PNnwFf^>zR5raaRDHd@rw%Rz8N+ChFy=XMP{qINDnsahC% z8U;Fyfq3uLa@E&12!OH`BByko&K^C3r#)RfHE^0WNJcj3{Vx7+l)TCs$-;nejgq#G zNK$D~UlLRqPy^qqgf9cU7<4yGq@CppIHN`c1@&b>UmZ31p^^z0m=_a5X|E@byl|<1 z%DM+~t8Z!*jtr=wC$)p%B%n)2ZRp*U;8AFpNaXz_ux9}zQa98C59N}FDW?G(ne=;( z&l~SNXQ>DJ5u3f4)o-2aJ&3UKh37>gB|@ho4Rk||lAc#p!;pv7Ct9WOQ5X*cU?URg zMtsJB>o^*LIo1OO)9SbZ%?)x8ClYWX5qNI6#?}qU#cb;D0G$9Cf@u(M6p)2jDM$l! z9)Y+>KwnZ9KMHE)*5q-F0`U_olOh2wHn7ttOIBKaH#@bbbNdOB z0edCfaUKOF{7x3xskg+2s+c`})eiX?*)y3BvBieo8HG)YL_Rxu(O3$@+6@59?A4dhkOA*dT~&|szZoS<;hY8idTVl(uwlXRX5VZ)8V zQ9ut2!yXTnq5*gdUU)D^xY?t%#sEPzeJrH$hIsIDC+WdaOQY#TVQs(qVsC?7+p}Zm zuCKKtrw*qMI$yI3k6Mz3?DtyECyj28)a@z^$)$A-qigut2L-YH*9t3NDNM2bt!?-X zk^lht8PJa%LzawoDj5Noy~UVbX1OQArs@HREkhLf6)ISqhJgDl<}aKwW6_dveHH+o%f5!(aE z`N`JK>JJJnZbXe5&|N+6bG1q8 zq??rn6~RNR3tRHX-|i~W3KpuKD11=f1GyAXh6SkHO3|dKW{s}YUtJ{K-|r#!^AZ#m zQiK^>tshR9dn;0B`0p;L{)&&z@{8eRE_tBkUbD-)5#E0*7_n7J{Z(n#RoVNi@aVH0u4&$1!xgRRbg${XUn6X<;de)F2(KI6uR5!y%F_(Bc$#lNo+Glf0N?68Fzn^dR(-b*u9zjelzvo zW}4VmhW=KT>sI#tt=yum{O+y7_gh8(wrFD8R}$AtQcKGMVk;*~%e%M9x!a8!+h){t zch=9fuAfycK3h;fqpCkQzyI7lQP~+#Tq(Bm(sjq&Z0A|P&PZLUBXwu=Ux}M<#so6j zPUp+O%`Y>ql=*)<>2FJO(p=x;*?a($dw3w5$dhvIUy4+h-$6ET6J^odb~Y&ag` zDdH%&9sRQ^jctX-YSdc##g#IOWnrW4EV&^F^QCoocK%(G5fS=T?5ly`w~vlrf4(QJ zFyS_vto2M1#fIa95k>F^PR>KBFm63met>+mC)@$p(|q_{lX`N)3O5BHHkki$v_jLAe`SeN46p6W zN3g6gNY{x-R`F;v%#X&ON0%olEO_Kq@yNZpBnqBAJ{R!#0p-Pm--eERmWZDuI@_Ix zzj-++!<-rSk11l4q}M#ugbPV^^=ujmhuM>{8^@SG^?*Z;@V{@BDdo5Kt0qZx0OZXl zfO|F^tIO8XB3Q%4w12N!Eu9g9 zb0)jXP6&x5!G~Nji!HCCAI>`Na|@inBKor?&g(ZeX)x>eo#h_xTvBbf;xLFStxSqB z$EPwXXzsNK%3-Vf^oWo52i^`WNfz5VAqE`IkMsk`SHb#3(qR%)F4==$&3>P zKfTX1(%_8R>*c&dN4sgz%Iyri?5~2~Ty5E84gZD`QXf$o`a{aUJ#jaL=Ruv6Ph!D3 z4S8E|fBGOL=&SF~QS&2F@5h|O-!)fL1h~(CeF;Ao^=;Jtx%uMD;h?wVBh(P)>{mUw zhKF4nPa&9d+67H$x;5=;TKO%@tzJd!&(wrHvtUrhs$75Ps{g$&HS^^mAt*n^8sS`@ zjC$(q3yS&bF@{I+ZGFXnfqG#nOx42#yfrICaVm3pTn*Ny!P(q9Yhrc3i$hs*i!Gu( zg#SDrR>g*+%*%+_M?`zp>$pDQ%YF&`#Vf!~&vfgMRZNj>v9U!o_Aju(OF5GZa5f0p zBMksa=nU~Ar=QD4*9%k408@gw<$M7RQu_NIM~c1O?8#WF*bZ3BW=$inzXxroO$|q4 z43g}L*nZp^-_J}Lj{0S^&+?Pg2f?V9qSCFV6jdpGdd+-JRbf?(r(O(L~zxKGa!@Sy!Diz)4K~&sUqXZ-*4xwxNoJ2!(GA ztIE2k=gRt36=rQ&>#n{|G@q5!e`=teU9Oao>{qdOw0Rz=z?5y6(m-6=OqC}hGrqGY zyKNgAp0SXw*Wa%&FjDxVt^mynur8OZN6O8Z4TG%+$qDESrniKrd-Q%_CYDW(&$mgO zK#CVK@BLl`^2eHA$S{;;_}M9lF3yY6gFGw9(2De{01@r7I%yXOqx5kLLyg!d|shh?YyD zc^&(-T_OPy?+1$xC;%{x&9;ypZIjlTZ5{C%QckTW2eA zjI&%<7$YAFTFJfVA`M-6-+e$RzbZtQA5k&db?aroZ9Jp9%4Sln`m%rZZ+huYzXH=p zJ@7mwAKPCzKEp5d-RfM5mwvbX9Bh$PX;g!M`{Pu!%gs@v! zQu6xE*h%2UJm}EMBE2fw=H{>PL6e2>q`xL$kMWAKppdk8D_YycU}Ca;a@HF#aAd z(;BqiZ04`E^)fM6Yv=NewU72U%B$S(g?rTn) zgXftcg}&apPod`yLtF`HBm5tJTp;q25jXGbd<+Y7nPX(W4w-(A^ik!Ba8T~``e!u^ zsTct86qURIr<1g?29Opjy{Fe(W!Zdfs5eu&cr@tI3cV7IY2wGr-_oDxd9{M0y->ui|GcE4k1ikeRb2JqJd2k z^7iV1zS*|J2`T>5_kfrM)K-uH^Xq{!wQg6Fe(V3Ze(onv#>$nK2R!+UB!CAFPTY&T ziKnRbmVgm2znwm(P6wDEK&&0Mh|n64aDljypA4 z&nA8Dzt7Y^i!cB6m3_$68@W}rZC9nzO4e6^&a5E0FmQ7wfM*#JB*?j{rq6@#E^O5v z=Z4$P1No_7M_j4bCX{!Wqz{OHQu^GOJ6;F#(hDPWTw1_h)=}@Y1(n1`>xK)Be?v=> zNJ>l?iluAnHv?P`=1Cx{yYy+Ux0}`|o38fw=q2gt`RN(!GH zrn(9W982b0w;I$kO0ryr1-Zd4xs=_+58|0f9#kBW7W>UkyNLw#!@#VmV1S)g7&s+c zKK_uT%QQPzMP~^_!6c&3`7h-FoZ^m8RwQH`$Q=XsXHblQ3_dpV@AYX^Pt$yPbBRE( zyBm-v4QRNX&q@JM?1xVtG-Y^jY?KwcZK7pXc$G*t)uW!Ce^nC~E5O(nZ3}w}R;-fl`d)g2fQ5EcQQn{JfZkqUfQn{J2 z-e%7+I2wPi%Y(pxf|qN*s9)%bgxtWyuwsEGxv;N#lZRQ8zse?$nkIk$5%ZXD{aUE0 z-UA_SQtbLBfl53Gc}RkrW|tHb>cxbGGU2gI#3Lq4Ig|ATlWl;>KFj3z$VC2Nazdw2 zd{bO9Q`{O;JjPSJm!|l9A^A5LsFR*`$I5(@wOnXYq%xR@erSozM(xEbC>HkLrj=1_D|37mejSy6g%6iK%0&6h!9ypqEs+E^&Cxl9{m%Kd@?3 z(9?|*;Tk;GjOFxCUGB|Px^b*V+*#^|)iW9@{)L^1_G`z$WyddceCEAWxI6oho9srb z)eVCMQ7#lnC9SmvCXImwIl>~MWs~KdyZ6`_%K#HhJZ;##>Cb2yS8D!`>QxlS!`w?* zHg6~h)=vCl*JkS1+_*hP1=x+XlEk`c^LA_5vR7kC@$5pZ*+N{F+5p`-@e8XV9Tr4{ zsUJGMV<@#j;q9Ra{y?s`w3O3ASGzb8Ho_?or?e3&d(m&uID&P;F>c?H6M+IACk;3X zamC_S<8a|uy=|WGNw}`@v8)ed6u-TaQs117ji=cRCYn2KxxFp-Nvxz_YKgsa35zkp zR_g$q(nFszajAvx-WFXIevL`*G+P7%5@`(6W8$lyNvV(CmHN`($F{zg70r#&&Lx{c zo$(+^Vw|fPM(qn&f2P7){44H4JMy0ly+lpK3AH~ww9 zR2<)g?d-G!x-UUDP(Bv335-UGMX9XZa~FO96a+L>in`}p(4*(9vW|H*^C5Hw|7GD4 z^KL|%ZhG-E(UU_g)`EspB7PRi-qG1ls`EJquQy1DJb%k2-t5v&DwGM3uv(5&p%IK6 zOIxN3PY$t0tg=k0kKYyx6*Lqn?ILir;r z2yy*yJb3d}*6e7uPyDyd^BEL(p^6nzTcIhZvZ%H-unqRH@LXWV4bJX-uYga%;h*IB zB$MPNgBr7f=_FfF4`y2HZnfaq2%3KTbFV#&NeRtM2y?BP_gK3Tp))N>>4Dw8;?Q#R zBq4DVq~po?%l#jYE&4r|B4HD}Tq@;Uo;djI5x@EckW3Pz9E^wfFF*Os$~*qcN9=po z%^j-Bd##0NO#bCn)$`=GD0yW!ugT`>2s@W8Yoab9iZfVH@Swz zk2BD>RVW`|m{hX@=~&4-FH_s?;q#)TB>qL^uc{|>$G8|*t)$Don=?Mdvm__qGSLj* z@LlSiZ11OG-a}!Qr$k?gHi+_&0M7Do2fEwCP{o6Gj^kadPs&Wjef!#ntX0KFbgJsa zv+63g_Gfn%eV!{AtlgJi*F2MMyeTVs_(`8RS+2Ct&Y>#C9Bq^?l~lxwQQfRJs14u z8O#HR#+STpHox3|)J*+--|7WHw-wozIHGjt09!k)Fdgm>%<{iy0bokT-T3{LccY5W z+iVOicdQQ|bNQ4w4+=tE-nq1=+%Ok8!gH_W1An{r`}emydMTf7w29t)3ii3Zec$^| z>c-EDdm`sZ=nsLw-RCn{%GF$$A1dg31m%NoAtp%iIKl(9%T)dL=`_^gxu}GS|M`H^ zpQ*TOL6UuzUYXIqGydEDNBjI{Smj#WU{8q#e0LG>)!5GOYd6Pt>n1YIZa=QhCy7h< z1D9fC<+W0P(DMGJhP}VNU;oW~{f91f_5Fr!+`p}>=6$aoaUxFe!>XwfpEU>6$L&@4 zX0mK-4*b~%Gxh?ERAsKbV6uO_x%P~+vZ1I^1^rrOwX>IV^SiP@5TExq;X8pzq`>{m zZ~dB~w?1_EGGRLirM%6dIx?1pd)o zw>f`K-kMevHAil03Yn4K?&{c?H=LD(lb2I77d4LGR(;REC3LSqUVX$Q&vN2N)rw^f zuI_p>mP;Lee~+Tfrx?ifLT1rRb`>f)Y@Hoq_%!xMIKaGr1QC4d6 zpBp&H>4N|`F>3TzYIs|2K^vH6cM7W&vZjAuAQs?w^vLIE+d?TrZtF@;l}pkLc=_^@ z&aEUs1a8};yAS8_^01`)pj{TnVTLORR*d=ZlKkXA;91yM*@55%l2BzM|1l`QaX2tO z^yM~!eom{v`lkxAxwW%R-{&yyy6j)~L*=`zQU7rhe`_u{`B!tIdQIO*pM3B{o|!(# zy$qlcHX5-B-T{|*EypPz8eoG^;_Tgha$3iy^t#tOsPi4?Zq^ul>*%RVhxp@SSPxIK zYTW$j9` za4ZVBeMS%#gW!9PGx8MqXhcwkdhW7O-GyFoc;_V?iQxDGEPNtnpSPTe&N_XiJNYin zp^8$Moj_-rq7^BlvNGxvj$-<)YerGFPzeKN4}(E8Js4Tc9+=@dBQLYZkn(0JFU$;N zT%mzctA)WA5B$bra(!oP_^cr=$89VUR*S|IV_NVD7_JMSSX4JcA+650t}Ug5`LK`G z(s2?EmI7+B)FkH@u5VPO9rOgRNU;TcVgyQkk~Odjhzt2{b*T2~e`lhDok4XI{IB8q zX=*JpE2;t4tZ3f`=_`Fy9!|6Au(IA9-&K#x;k=L--ayO{Rr)43PV!fP=7wqGg9A_9 zA0fOpZC~Cj-rkD6!As`QImA%7EN~LBe9j1WZ-i4UN@`wlZG>+%cMmALL|MzV9i^{k z6B(kI6By0ja6&y4BTWm$i>CF+ET#3ai?Q5mVAo#C@^CO{zB*&7@zMT2GpNX;;c=-e zwcay)v*D%rw-8fabHHOm{<~$iW-`(sr4{?v@e)mFhCzZHcQlirGT|r{W`8sMk`-#$ ztTaVmW?)&+$QLX_pfXF~TB~%A0w)6ZP3c@ygkh>?E<42F)T$zwo2<)}MB=I#B%2JC z*(!ldYeF8rx&=5FuQdx%kS#}CZAixTV;b13SiAsin*BuXA@zQa@Fif!!O^YyK@MU2 z{9DbZ9u>j;!U0gKx&^z_xNntn86v@=x(X3`myrW+wM|j$Xq`&B_EFY8O>B(%dK9^> zkevoA43|p9X11MXXOkU9#cT6=4Hw5_62pZFRZlCX+WALW-TVdQh~{$Qx%GWg8&Rkw zBJQY6ig4V=AL-Y4FYM?hq1tLq())D8>(z|&`a&OlmTYc%JyA_uOTLC!vG@d(Merb% z+QQ2+?RmF;-suKaxj-W5ry<2D-5rV^_bMD8zT3t-aQc4Kl;*ftpDfR=(%%$e=PoA z<>vFtbH{&wAD;t&{O9umCpCdpdeECJVn5|%a9lyq?qj%ek6cX<{bP|q+B3eR|Zgwgj) z_`-IyaD|LJC|Su$N%H)SM^j=4;ZR!wg>HiTl!ekQ8IcSYxh|CQeW1;28GYA)D*QQa zxY3}&AhUmU{Y;)=>AD=sf!?RSODxvcr-Mc@g92&HQ%csue7$axhW~nB9m_ZRCtiyB zIA8cJ_WAi$-TW(_@A|1JMym4Q*Ye_Tal}+{F=YZ81DDjV7lOayGV%H>^OlKccNgU$ zltnQGCRF00`ymCf_S1_;SSuLtKmU}dGSvt2TA|z*{T_Lu&h}M|Qr3erO@O8n+(E{y z_nsTH>E^jIxSrN)aA8^6DtW8sn;~h}b8ftjRaTyxXydaFFmsgsdd4UxVlZ7ZxYNg^ z&xGm^Qpx64g(&gFOhpPc28sAD>T-Rzy(`IC;$2EN{`(7an^a<;J0FYdoJt@^Epsmb z;EH9>6%YUq;Vwc6tZA47M*yG`4H0S;11!$cZkIS7%WzW-QoRtz8JMFW7@CJ0;;?sv zTO;8W?`N8r1198>Dh-O8kZ|t|4m)U`S(Au;QIgm~%2F{`%j>WD5vL#Nypm zM(0Y3{mgUDPeecQLbWy`qbz@6HbFZTQ-4d(BVUMaR2l)y7!P~nGI)>Ad)o%#U-%Qy zORBqBo99Bem@UuXhHIj1c^vQ#X%K!tYgWnF(cRaKZDVg5D3-1phS zd;a9>X|*m}BOD!)Mgxjrf#jg0cY9*^md+nvR`(eRZ@7C>RyLuzbl*!Jg0(JL90cW5 z{uxRXKf3t5y~cF=WrKy!gQnzCn2t*Q)qPS!YOG(`Dh4TYFB&bUrsl$B7j5B27O8WS zVc`lyI@4C_(s|(Wz8J9K*eSjyJcz4sitUpmgmVI8c!gnLU5W=lbBTi$oR~y&aX0uX z%Jh7@uhetRx#9$F(^D}_avxF}xqL`~rn=SW+unpHYxMI)av_cC@vN^gp^v%K=2?k& zfe8}Y+oA`^yYG&X#hKdpr`)=_NXInckE1V6a6wA#rAo(Yj5s1_tN}hW;#ED8Lcf7& zsH_`&nQq7-$wLdqfq4RRFN%&t!+BkLgw}IYarsTZL8?IupJ4HdnHK@+Np%i9|jSY0CrWw1<)&dCcosdDR#Mdu#LKU z2m732u{fz4UVqyvOqD|#&#*`&1Joh{AwsC$vX7q{aSHdpc`b>6RF{5{x2Aau%Pv0m&N6N1FHnEgp2LBZ|9F6yBhSrS7(?I#vT*?Jn$e7(XRMp2w+7B4=w^@Kxqh z+hV>j7q;%@M|;-@hvK4=E1EJM6qlm0FV^f6v|ktsLJv-)yvC=AuN3x$){7A|?4+_m z@XI8)EI@KeoUr~RB`ZmK`puR~G7BEld|uK`k1)nN;koYNR4AsHHp_MskI6Fpr3m&s zOAX#%)v_fCXi{NR3E^dSD8*20i(689K&pTGPw0~2RE8#&@UJIH4cDjshwW$}OX=hC znb~6&NR|jBtB70DXqLrL9AgjZex+SssyhOG-`cx4K!IH*i%3G0u>InqBuy`Xw$Zhd z8J9Bt&8+;z>9Y9;;%&s#N(GRGb6$-#2Z8|^x zg62s{^vk*$nWcJ~H%_IxNZHC#G~Tee(PVCUx*47kH$1f08L@M%UU$_;lOdi%H zx(onZR>e;l+(X*w7w)>rYf6&$Nz#Zu^%;vi`4vBxp=vW=*m?3*4qi_j7&mW>*Ox1v z;Zg~KTs(yL0*v@;j?ZBi^Umu5YRnR#6DFcyjATe(26WJ zXyi9>!#{tJGdmxrE_uF=oxlsyawDsS6uGIc^!b^|Fp9}2FMi2>e#wvbuAawG4M8N3 zeG%FI#MbVCyd3uqV3F%LUEzPg#k#)%OanXplW2QfE>Z3U8j~mEj~Rkgf;P^bN-!(S z^?vv?K1(<@#I7=QdmuxzN(d_Z=~X6)n;so!FBR+6VS^9Ytq^D|@)xY~Z1?t>wo^3O zdLRrH4Ev-!{lw}nREui&NcJjvlW;r02B3$4;0w;QnxDe;@dX03>|@xa8S3vp0e50% zZ1IqN<6=o8g;s(Uf?PRBnZv{wT{86ayP&P=%{vY=_M8OzRoj{wXwLvW4rgrTC9Yux zt5M|dLJC^)sow3?w*9P%MMhR3JdcSOX#Xk@OO~J-3Jm~N=rJPvF_$~7O%#&w+L&{v zTnYQ6R#ADqFi@#*Y$>6-Y**eY5#}pw9P5z+OY4hKKOT0ItY~&IMrV;j)K5r$gVy{_ zTVZww*YiTzP;L2y(-M$IF+dw~=F(;86E_gNXr|3%yX?KhqhUS;-=s9L&#Z(B6ZIXk zqFwjyX|j<8h2!9>-;x8Wlvup zlr(Da9eS}Noo~1!LGjLhTN?*XJf%c#CD8M2aOe94h#>!AfHq!%O%EhYy5*A`*DeWh z-Gp8Xk?zO^%b7**MJLy`S(GvYDDbjdsc!Yz0kQn_Db5t z6L-0#tu#(BS%EIcO$0x@19TUT11b9lzec4Z8p_1iy0Brq0MYMts6?QWh z5BNhY+ciSp!bhjivf@ZP#-ZV%tfErzoc=IPtuZS>LNO1XefjYWV>*vC{-W|R`n>7% zNL_4#l+-KjJ=9CAS+-w7Te3w}AuC~qaq2Ymri2kE%1{FV#$XA%jYC=XuOb);2{dY} z@PKzh-iFqE$y*HxjXP^vG zd@J)#8$-xG-$yDF=ph}CEA$Pj$UW~07@aX1H=p{ZdSOh9kF^5BI;1(Q=Urd$=D*Ow zr1aVnEpUQumL-#&Lr^K@YHPBzToNIt_Z6*YXSF`(#($NF=Y>%o9=o+Gn+=`JQC_yE zAHw5KSB~;1S(NG}7Ac%RMfT`4m|doRS8C6fKv-MZs2iZnHGJZ1uA(H%2v*eIrmXS( z+mdE1EQUN*>Lhw&A0>SqyVK)&=U{qkJehQy*Ot-9~J5-g4(7d zKer;kdxkowrEQQVu6}*t#tOdO8sjW7aOK?aMXg~sOPe1q7Y@|F?9FRj6G#1rBV*2m z0Yo*u#3!y?Iq-)u*>q#QvV9bsdS?iEx*8O~;-J!4tGS0bcB92cVdO;f( ze+LI|^IWL?XyI$yHR7@(8f|{J^(1iv(V(a1n=D|e$TO#}VP=4|L(k`}sb3EPm;Bm$ z4}Vd2k|zrl;m41}(hTX}S~HaI9%HflCwX8$EKuuqaPqU8B!Y&K=}ERe^G;jN;ssGl z_B4_I=$QYmx%Q8dC{LEmX;EzjFSQGY+6pJNAJ4Tt{-9m7(N^?T`^nF?C&#}Mj}P7= zbl#zkScTf%!0jb{$eU6}WcKEpoOeox}f{Qq2t9h-DdBO=G(e0cRE@g=(fgpv_8~r%jsx)qT62C z(f&-gqot$c<#FWx*c#l4i^9}h^wEl4%6e+TDbbLmWq%?!o?=Z*=^CP(UUusdxB#Wb zFl}Bep!M|ciGRew&8t#00?UI(JK${@eNvF2=i_%AsNF;M`?;@yOJ_nP(^NR3=A$}o z@qbQqC*SpYH6TD{8^@TO(Xaz@;N|#0@ZI2BQQny?!(^`9o=K}In+d~*XLd@L6#u?b zTj_sdIPheA((;b$7e0akL;TBVM;o8E=iH4y4y0(-&^$HOU{Z3p;VD`Uqd(VHFGfC@ zORGQHOEiTqOlS<4LrgIAVF*U545zu}##JTB=jP1>E~&~3l0$oUYZLF)#H($tuPQr| zMHw!$$Cu8JwFm@tMeO&^y%r28e&pQ1*Ll9yM{INDv*l`^F_B{~6)-PSI--Gaz}XXE zL{J#iess8-bbct9L;CM(PN;iMn98e2mdgbfbMD^-Kk$cz4!rR**1um0b<^f||Mr(? z{`S&T_m{Qq-D}{l7vKEc__ur8Ys7vo)GH^AnB%7LquPcc6;9T)k2$l9S^w~J{d#BTrQuh`w!m(2xg^!gBIIZ9XSi{z^73aTMZ_32!X^=O1WUTU|bAn2YW>TVej^xW0d6Qv{fkrWr) z?`Ti^SZfdC$8g%@ULK*qjAq^RqdcuSDN1Z7sJpavKahV_VRo}Pu^b?crBgy@#t&c+ARih%0mm3ZHR{GQo<~!_5YeRiUD;bTAD9$l$7m-JOqrhN0|L5 z!SAML#>dLJ4K9FqqAEE#9BIansy!oyIS!V{Ur9ck)d>d20AAvZ-G!&yz3dK;UeCs_ zVob|2`lGqC^D6u=B>o%;`rn+>B`Fr7pTu@Gl*euEUEb<3U?Yh&l^!=}cA9;sAzmWY zaW&!88LP%js(EdWHz#2YEmR$KkpZabDXZ2Q{uKhFgx4b{{^<`Et#^I$ z0GtoxzsXldEsg}co;mGnjZ4j_j`zEj$f)sWV+J+6(p)JVS*6SB2WIKZyCu^v|G^B3 za$?5@M3hHE%vJ8_Z9`^v%c_AjM%SesY>d07JzgDm-^?I4*7Zp!Y2-$f_GBltgIMo& zYi`@wyx2#773)3NqI2fA`}%!ue&zRU+~FVQ(?IBA)Xb|{x2eDs50U0$50|^71IZ-pMv*sjJqRi=HVxlGM9cKZ;C&m54Fj$6Y@@* z)x8OOqSB}hGm^h*rOX8(kO(}NV(&~%nf$UN(cju{fFY*hW)cD}PfbeQ*fhj6+E6)d zAO9^Rq`t&|lV5g3(X&;$$a^;Uqqek>R8$#OpOP#abahd+sh2<7?{-Pj6Oo4{DW|TQ z-R#9a4l3Ck_-bSuXIkYB8YUtisI2;`a2*c-S%0M&+NE0Lj4r(pdn-fsi$?ncukJN^ zArZ?q&KvkOKMY0&G0z(7f@X&{HFuD)s`nmd$=C@em^1#wW~DaSYiI8lNMwHlh+P!= z*Bmw&UzV9c2ogKh<$ZCo_5jWts;0Z<2&; zqQO5hw0rw{Z&IF-`Gi+Y4TPs3UcP?HPuEJ>#;02;eC*ognFU)s*MQ-HUHtVOcbRSz zK?gAg)y!U!=OH0U&V;Kn)&MAf%=vxdu^0&*J-?vmZ!v}|Tmz5VmkM$+2gS??g0J@m zMTVfyv+cg#{T?+OnCj6)5_$?3uNko`&@sy$nTbnq@jMgxZ8%qWIxedT?H^G!3f?IZ zUf49AP34})Q`h3m9{XPUB_w@{v?lzzHPbNLB3h@lH@3lkUGbam=;Uf+c1MWQO->s` zfSaLSj1V){Iq_sL_@;WCSBkkKcRoaHg=@*t1d?i3E=nhm>kvlh?_s2y^$)T0I@>aN zM*@d$Q;Iz)U(Sxs@%^3BY_!oa6P51eki-MfrhtLxMUh#t9zOs_3IpoHUakKF$2ZR6 z--KkpiMwlG_V>rvKG5Fr)UaEVY77hU$WG@H7hp8Cam|G1tWoNGb8|Xs7rK3=v^8nY1_LVUx^?rmx#cz0ou=*?fOe`)F7W1spz+ra^KTcfEq2?t znBKgFs_sqRYLY?r+YG$bSxHu9Gr6a5ACXk^iM6)AP0>+Cs+bd$v;+GEpxy|Ea58|w ze*a-;ZV)Zk>{Y&FskE-6YLeQ&%Y06+j{wbsKMbk^je0`%Uyg?zJQsPsvLASzUG@;9 zl`04@UtWNiZT62&hr)SK#k{H{hI*I*gntG#rrkum9EpgANcJo=?MZWSuC7R*QE|#h z>!Ee7JT4z85ZwP4)Af)W9yn9HIBGK+w9kl?gwU?%%=4i$Dr%l!St;&Us(TN;3353H=H0my#dLD^hPn!5LdxdYW&?fGuQE@$zAe7#u@#Z_jA1SEQ~wKlu*ZLfVIcQ9^j1RJVe>L))PCM0n2* z2>oa=Mr$S%6|073K`Q^S-S?^@`qV3Q{ye*vd68>ohK4d-Q+twbgYvokiiN7C+ zwgbYbyWR)Sj{kj?A9NEMHV`35>i??~?k(nJ4y|sQ?_n^g>f*oruDdy2<{6C)FG#<(~?%$t{Sun=FYi3CHeczg~?;(5k zosfNt8e=f_v4kvT--?hdg~pnMuRSCUWr-3cY4vm8_y6^Oay_}8Ue|e^ulM=>90w$t z#?rV~fU4pe@!*wD`=l)kY4Gp}bm!g8rt7NYed^n^hSrQ8WQzAVFfjc%@(KQfF;?1m zat+7rK!tdtk(0ouxH?B|ERqp8aZj8{eHESrD91l~v{D$#uP=H>lLc@= zXLa%jAnqP@YqSMP{KS|nzzkq%wqmyo6ZqV|LfQbz`KPajq2c+z^?-C4ZD@{g^lv#& z-f#?84L|UcsGzmyay#~cr{X39WrRiOMm2kQ4So5=cFKg@0GfXc4VFhE`#iX(j#x^P zV5p2dWmatPR}l<7e4Y7HT*sxvaFX!XOKi#9|6tRx)(};UcnJm-;wxx6Cr59!?>u;M z%F3>MLr5C$LkgGZmB;jcmB7pi4Tej;?2w%LDmg1JbzTEw#!0?r<$oKFg$qebh0E>E zQIYSZ--XNk?2tM8Yh8OhcL`h|1D%&cd`m{M$()7D@jR9j_$G%@kiQrqFZNho>YKcr zf`U?ng4$yRt#1l=1x5V`MdQbc=HC>p6qIZulpG%`xqMUdP*C=XP!4#k9Q;i=OhF|o zLM868O4Sqxc~F7}Y(t0;hUoAEzIqU?F`3_-toKB5qbhX~>P-b|DR@<`WYtFsOXENm z?aJdqg^Z9njxM%3dLi`(3R;U1TDMuXm~~1I%sq?dMW*JT*raG3DO~S+l(8Oba6=?S| zPDO*mYTh#k0%L_Zq94Pt`Avh>MuywwqQlU|{F=)=LzvLx%XqrFJ+!zpumk6#S5wVp z7I`^O(fE1cj~r+j+de|){H!eT66!J3f7|37;Jl)MvUk*`nb~G8`mh>N7vay zzR1gaDU7h&>=x=G%#5YJTibr~3<1koe!glmdbfEee%df}yjcu4YPw}*8c!9gPkQd% zgi^2KEz&Dpl`f8kh8P$aMUMFjV*LVzi#zJYDz^z;l~FN11B$@{n#t1L= z`C`&Q+I;0heT5#Z*-@~iGN;~JoF*2IES1d)0nuGHua$#>&=Uq{ANJVV z-c$L@iqmmpk6GzXl#9@2sWA<-=iey)jizb8Rk{7$UVi_zY&nnx)^WS4g}E~9Hq$BL zw>1IkrDO5w;^(w5|QZ6L#Q3$K-Lg0Fg6Gu%M=di=JYAsUj zd9x?0c!MXJXZ6$RihP```cJuEv2uW)a^ng__|HPRo_fBy#fl;f_UmVESGswY6+!L>?c;`s3P30@v%vRqN z3bZUQbu7m>ux;PqvU`H;;*mKX;t{lDt_SiXug_OHmU;}`ui&}vT*deuSM<29>cZ0` z!J(WN0DaqIkv%l3b&!wPDLK8#fuU9kc;0)jwb@x`6{(H0Xb&wKFH?5H zlX#<=6$Ipq#p+^9`J_!va){hxhPL;x;`KvecIr~4bo`%cMZ$U$?{)^jy{tcX7LTf% zA-9b3A?M$NDH>;51kn*D>F^WT%uH0t!>a!lLc4yloK1KrDbnoDXEtq;l}aH-2|xKi zNr5bC)!pUGHvw~vA?-?)?RlT`3w#_)w;V-$S|sQ|<#_I0DP-f&dCSusW#BPX?IKS@ zRK9AtG=kzaZCO!QZLZ=X;^+|@{3TZ|T3&l{m*qPCm-6ufgw>sg3M})c@)!j3e4=yn zjrZl|o71~ygw$wfrkd$jf>49Ow>SA)F-VjiKc%XK%4L&oYv($mao*!_{kXvY{MKqosQx@R)=bouCId=f)J44O)xq#S%Fl zrCXS8Zo1}T!>wCYI}SHhNUHl zi@iWcZw=Ioy-wA5b^uV{2>r1$Uj1VHLiM=W-RHrtomhrFzTDY^B`|+MqO43`B8LW< zH`9)zN~)j5`2b2i$*rh>PWnT{1ck-h;2~2YFX}JG>o#f~`!11!iM^2I1-Ze6=lf1a z*JY`C>=T$*%sOlR6H$Nu`YM$Qk5Osnsf$-!l52~r=0s-zYEO5x-j)5Hpr?S_s(736 z^|?c@nVy19U1TFa0od=Y#Yp-d6U_WFUsn8WZuWdz4&=}1UJZ*0=y#GmP#y^on*Q>M zIj(6g=HZK5pR#2=`~yXXXS5zIYFVSrUL6RiOdcyNKp!|lPN8HjUk30a*iN|zHz)K2!`ih%aL+2Vgfbt%@%`CxW{wt&Fp zeIoXywC4rn*TmPxTGmPqc8%V-(aWNcsdVLoUAmTvX$e zU}iLA{fDI~k6+C)z%d$fuZI2M7TWp@U?P10KFZT0@C)O?W(2lzO!pD-w-WXDTPr?w z;1%_aUq|0XdNvrQTf+gKE45$<^Mab8>`XC2vYbVpd`K;c;D_m`a$OqK3t#X2h_yZh zq(qERDrdZ=r+{pmdY|3TSfHFFFo=P7C>oI4jeuIh9@w=ZRU)v6qE&sA%@Zk+nOFtA zHjzO@E)hq;B3}Y6$*iP52<3;%?dLKwtxV;X)h9u3o+dJ=w666=?ypKQR9$%zexA)5 zq2HGmf|Hx-8JBj^zEFb7?ht(9b1pEjo+1w4Pnf3? z=Yf%`F%etGZJ%+NgXuVCxnBwRt=}NKup837S~yCA8}4p8;e~qJO@qbF?cYYN82htX zd<__L#B-2pOpFX2*^QK*ELu@)ptzYD)#-;ujFvG{FTD#awBbI5))vM-ckEo#eTtll zF4h)Yi)FLsUk!3BW-Otk`<4c_zVs~%8G!qhhli_e6ky40FerzS)s#R)^(Z{yHqyku zDpfGUzdD0+wXVQ$W{63(zmjF68e$t5P+uA{5zuh&79y~*I>#iiss4Y(HginHdmKyOxLgYGnc>1~5VsJLS5EN2J8rT<7J+8;VMrq{max(5 z>!E&J)bwf$-}Q?_967fGdvzG=uRpQdefA}lbm($n#EO#m;g&P!)2yc7cg8V3vQt6_ zSh`1j=Ha0h^jE`iNbCj0ZsF(uGL+y#beO>@Zqt+UMg=!^y)b8{M_U=PtPk!SS8_h) z&!3H{!kfJ)NScgt>Obe>j$%glg<0jU!1)-i?3oowYwLbgu7*=0I)}ogTznR8Tl`&I zi+ZhZv;>J;i`wu?bTL%g?7^-Y;aK%ffRq+96kTqlO}e!71waTWp66wlO%!`|wo1h~ z|JfYp2zfY55H71Tt=93ZDoIT%5}WgCH$9mNt0{0u77bC2s9*#_a003w_Z39&i6xKw zZu8g-Wvll4Z#f6iNokEK;g3B(yn`HY89j$oVX{=`Pk$z+p5G!cVC5Xox?&d+z zA)TiY$A@GN@!@M`0%GGV|;v3Bop09|!F4PgC{yahvqvG+^Q64BhpKBN&tac@<3+2l{6Z zL{f|jpadrNyR(@>=M+BTOIOC;7^G7h8bn4JT1C6(n2c9KTV>xNqaBmK{;cP{A!MfE zh|V!tsDw7tQt59AU5Q^U5UHa95Wfy*D5y^KYk!dFWw2_k+#Q`(2?D3pq`0!K`IHf zxT}xywj@WKrh(=~=`bu-*$7xc$yn{0$|aWRFc5Ru>IV_Ff~O1htp8hTWHJHfq-hgd z-b6Nw#$$*G^d|p`qk+Cm>FnPMaLUGA_Y3DhuQ2yQy3X-DahYqB>VGXY3!U4*f4s|s zzR+e4(U0#{F+D!v!%UJrx~6a;M<&aqj#r^$(wk^S6YPF|hpCifyvGW-5~G|W0TaK} zQ$w{xgqJD!hcM4T!^VSn?%;S8baY4&?zuG+XN8Qi{pn1`?847h(s@nQEEg2U@Wzj3 z@8QQio`b16+y`r}#A)Dt#y>X)@}Ko;B)ytWV8+fS*{o2|gs!2m3RzMHP0WNJOau zHw0unbcsx9Jhf${YpJmwcm}hT&gAW~@d)ta$JPlk7Y+2C{1hVzj8MA4D@tkbPrq$K z7c$Yy+`7@-roG402FBZTIhhRAl@P@=IxgvO{pKnekq4g#Sx#i>Mm@-^-*x)xmYv-N zC%P&AC)OMyusCLb579_%jJGxUs?~!h90CL$=aa8$f=?MeX=dFoRz3A5zCIyBwi!l! z4!kJOG69S#19`gJYMVDn(TI;Cm?XfN)Wk-Hs+s)VMj>ab;(haQ+{M6c5&(~(0G$Zg z=xt%xCC+HV*NZg7ffhhhMY!B|eIdc^V~PMgXlBr+<|$njoi)3n@J8EJ?nIOg;oZqc z*pyVB?1NN=RxPI2sA&y*%L_t*I10-JKm(aYTH(>>tiW=y$5LH<54^4hNBU_97sR%= z{8fMpRq^qa4n)>p>J_@G09tI0j#0b*cIafREquok-t;7foe5WoGI5H2{M=e+gH;Ip zf!w4<|DG|VQsYAhT;bV1=V#M&-W=A3Q{ZOyXV$^E&};iSUOL+0A>;K{3F{m^W+EF~ zKTks4874WUJty8^sNL_>x6%Fxy9u1}Lvr8?>~HAU^!F(UGSE zX-Kj&dlE0vR;1MOF3!!_&zpDiV*B#}bcT=U!D~A6={8-@Anr>VLcbYE3e@&c#pg_) zAR5$(=igQz1-+45O;48Qb)9c6c!nO9QgIjy3XQmh{^~I}5*6m0KA*g`=lJf|v&mab zozL?=VXCy~_GlTAUiVJ;sRl~Td4t3@>LHog*gd)uan^%Hd45H_9rg?-67C&g9OJ&+ zzL3B|(H2&46B+FLme6+Cx6=$#za|-%6G$o8rAr^KVU{&}|5Wmh#;-8E`|KKT=Wjqf z8hUSEFTi6Kyo0;?(p#ETa0XaAbopcL$}k@|BCF%s9vy{4nj5= zKBH$HuXhMPiTiDMbCH_t!Q#SB&9L`gdpcn^UqH8pUYRF~#n5Ce!lReW!F zYkrOa?*($BGHLE2UZEUjm2Q(cIr<48o*C%-BMy^6b_+SYjb8%U9mFyN)sVYhH^NT( zX0vGt6~Un;b3hAFpQueItBda!DT)g9J9s5oD#&Z!-2;E9f00Y%k0<78IQO#-K-1}sURgw zmd6^jbTYfhnH;kzRSjC}vN|Z*Eu>%S^FbCtJmh^WhvN}P3IItQ z4x`cdBsW-PF>J*bmDx!YL~l-852NH`7J(xc*03z(3Ww4ijt~Hlv|Avn*NxyyCrT(f*&dcJMiS*m;8`C)lD1& z9#Bg3V~HQ+%4TP65Vdt#E_?oy<7fK?qnQiw-n@-R;Rzp$|8)o{QA@f7x#A_^2HJJJCwatqGN$S>Ihb?ysU zW9NGX=YH^1;mKdU1b_%3NS?53Qx%yAYeKPBTO#;=i3t3v!iZmVV-=bDCL+3eOB`|0 z7h5g&>yjG^=|utZprGrNB>83$#lRZX=9;VF{~KSkUeay8l(2cpnpISDulB|!{SW}j z-C1)bL&QqGuGO;6>Z@p;yckQDh>N&bCFe!=z&gK-`he#8>l5|Cd-XRE4PoL95he{$ zfekSk4ROs4Hzyhr_Zn^^&iNgU$tH~{fsJVyjp@yenG=oK2uXGV4EUij^_O%amFY4& zYdjk1lPBk&XVR`C6WK23FW2lpC@pa!Qju}*`cYFTHu?6|vy0ZUvS&n{8`i*TD$|;K zJ-tFxrghUYp^2`l$*1bF-)wU$NFg7=<&exd8Q84MeQC5=B_QnKjZH>F!bRLSXLr0} z=vUZ!GR|YRrN2~E7tT4X&Us6>CH+|3x8~su7FB8_PL942ccb=GuJvp;}LBU;ekM%kg*?PAce9-MqE%eWxTPv)l49wCxm zBgS6Aj%uG{keYaxrBTm4I`-7^>BsHUIwv+J*3*2PBFc7R%RwF~-=}2irgr>?6|4NR z+J|?WL)>Q*i+;7X7CEtVyM6o4QSe@Fm@b4G5&vq2^imkK9yR4tKXnbK5JKaqAh2Vf zc*%9Og#3ZY)T4iX^5xLNOT2|U&U;FL^S93-jrYD!!sG-6uz23+&?%J9`{ z(NM_Fe4X&^t~jKK>`GI;bmrUThl8$jDm-&t;rX9$lx}m-y}cMH^{`Bw=cm|6(?yW` zE4aD?>g|s}4CZ>y=R~^WTTm21N1k9!3#e%cCu*7Sppk`nH-ui?@T@2K?yj_@PP+l^ z`hz1#R!E(QQT}i9n6S5HE}_Fp;U?y&TLP?){&Ms(8SGF1-iO4Y+2HxZU^->)Z!Ygx z?JQN(Leve(xv15^qBB;dsOfk3H(f5M*8-EI;9$9icds>>{5t49(1Nm@m~{L&Uy@$? z*S}8qo1YRBE00U0YY$IuN&GLRwY&HxS1W5}%%*o(M`|0xJb~$MVik1?-*)LH{BZsP z`n_Vvd-Z$KGSZwS?l-hpqH~}eadCi$4N=YwW-0?TO=p|7w~4y)^wpNg{pdGMbco=c z^}f$?l0KIQT`uKCLr4mno=}c9D{wqz5=x2p-k9@MjeoP(1DyfqqZ#KzGncb-3hiNQ z1g2?R^5y=W#D67=2c7{P2eu%2ySG|}A0`6yLKX=Rns{gk+x^DfhFiW>w>S8v?kG%M2w_>9 zfhLqB7eC>(K1EG`dk#gV8p@`o_uo!Ztwno!a&Jt;KZ}&I8^> zlDidDkA-!@!ZU@AU<=)cz_x%37h6%J)W6T+jjtg|a605P9m^r!DrrpL&C@l)+XCfl zQTc%agprevEKrkF*eh9lm}QEW)lOdeXHPjbYfEI5CHrf0GA|CfEPn9ESQ&fet5Tit z$5!7Ib58m3`{&pFP-Zm?fp;W7XFT`i%eRT|e8^g-i8-?eM~kjx%Q0`chth6e9}f&) za7&hmJ`>8aM2cT-3&0>cg+XqWh<@R`x4YBEa3yC_kR`v8$ z&exsG*Skw`nx%YQzH_AyyhCW=Ai$OH6$`~>_Hw5eaGNGwK25ppMRv=#fal(F6LVf< z&~pdH&=h7za*TO6zFBZzh|9Q*zaB+pw{C6H0|2j8GTHM%KZKqiNFmHlSB!9Xyh5QY zZioxqAy?tRzTHf!(Gq9>;d6ntwL?1d4JPg3j4)b;k+G7_#({2i9zV}RXzz~)tAUAU zl)e@=%?&mjo{S1LrqP(@37AYbU||WHkLJIJR+;H;EI>7iktIdhnnMZh-Oh}PF*`$v zT?7wxy68DT&YPP5lb0g-38B&!M4X#=Td2V2;cZwvKUF zwT+sUwVEee-f@1|{O4;uVO!I6*IpmE^u>KY*n0E&kt>4SlP+Wz4V4O`Sr5WOX?c&! ztfzSxZOqFRR7{KW=1&^;lB}PJEUBrqgG55s1cO;rX3drSo~<2EBvj^h2S$n9TA6I2 zT?gaNEmYFCcYM{XmZJ1Ox81u}maK#!bm5$B(oZDE|wSVyJ zux%m#RX}xF>(l*?c=As=U!uavvn;rGDOs!D@FVB_aANqFlVfL{{YM{i&36DT!uc8=k`e9 z5sBUO9j-flV_1Tz2C;G96#=I)Tf}ap${?3X;jKOCY|QVX=<~`bq6^-o*9E)f$_hq* z5-L7(uHmy+zT-n$lxpuh~aS@Yq|B}FSfVr=~#SF z$17xy-{X0^o55XgqJIbX^y|NA>HXcT5%M%{eLtk{_sQ=YXH+m(LTK-4$WrJKn|(sq z7+=hvuyLW{gzyQ8?myv^3a=9)rZs;2iI~ylN{pN{RrwpaaMeCBYUx_c->7A;;>76H z>)n5&*CJjg#;o7`@%M+s4@T8;?eaVLVsw)It+;Ks|J+LrQ)LD`og4_bPuq`Q-@19g zj2>8lNbcQA`1;D86Qm=#ufLVn>`}!P1`5dI4x4Vj{Qz>C7SY}hnx(wsJvwl9p4G3oaadZJd=OAuR_Tr5{ zT{l;B&k>^R^5#+stNv$vx-C#G3`QbSaLC^kU{2`x{WG8P!RK5jm28{bn?icCX$vD8 zvBhGqfHP=Dj&%?1*D%nZ@*_Hj&pQ0TLfEf`7uw(Itg`R!|9^>~t~LsjidnO)5AOkj zl&GoV?xghV2}yJzhxBM)NRB!VN3T!|`@cC}tgs@6o>@J&Y_ruJpAiwHcoR89 z1Z0F~ouep*(Ti;2ATLUEnFrXR3bg>BE*Wf~f%9hK-b9gYWX@C49iRgmX}N%-Po?_u zz2i2tX|cNhJCfh1?MyAtT8|lPEBwJ+eKy_Lww-wsup-}~ke4M;iTqHx3UtS0S+>KN zb{c_tcjZ_l+HnpylIWz`esCt5*RlmTPU{MMn^h3=!%D4f8Qte;P$dY}L8+-GMffaU z`H8z|D^cA5*8VchZIPk#e{tHXs6uDLYRCWXRa;O-K;+bY6}af-{$GoO!3#WIQ3gtT zb&YX%bT5`E7V)`876_3>Jmoh@1tLQfNWx2fn*ys#DPWen>kzehcRj<;o|8O0y8!u8 zz48#9`K)z4=55@J&v-^FsJHHJYuvuxrg(}BexdceM|_+2dy#ACCWb}svwl&PQ#bj} zLtnbtTOz5>uaY9(|w~29Sqx>hj=JU4jJ z8y1$*N5iIsF8~e5{fC}ak1Y|R7lE6iH~eMdAB9`~cm`EZQxK9|LHuXm)FLibBW+E_ z5hb5Ia9Oy`W{L2Nlp2KAhu>)zfrnHMo)v=fyz{5uN~GdfeXStY5I0LYh`|txF1F6?YSV)E z);hu;C4O$z*b2D9QPLbTswbjQ_3{d5d8)!&#!Z$xyLw7KRuwJ@JLwQ#*_60(U-U&W zd!}@|(AA?S%%LehD0=uavLcqI!o=y)WMn9BfAeNS<%H4rT^+&TyoxojJsf;48;L5o zauebaO3%iL?7DZ_$!K%tw8_Th(7Q%#EpW|pohy|Y)%tg|;uGX0@SA(yVeH5%*?H?s z!oFg@QshYnR_gt$J=Isiw<5}SoOd*K;{Hqg7g3pp3?uQy&twm%mvg*z^S}CQw&Gu; zpOU~{Nx`p$7K_KtJLb`j4Y7cpTTyLSKJ2&i-Q1pVEq(foG&LWAq~2Y!kBE@$z}FI-O^Hza-zzI}6T$Mwgvoy0GR zXE$k3x6|QEw~n%JCp_=j9gO{`YjXV_&|-U(LsyTNWk!{2-*AlYXpHwbPkj*nR3Fhf zbC#;wdb{}J^HGkGlAn5WTsgOIJ@~2Oc>8zVlTP2McW(ZbbCmB`B3c~^kAnylWPW;< z4(==YRnRzhsJS)FfK*Kb#%u4cWFG658p|S{j#EoEQpNWM5R7sxB#v-*i0Nh~L+xb` z|I1uFU+^Ut*+?mxvcCgNK|41fd(77Y?^1N#A>>?=4XO#o7nhu53> z-%aW>90*?96)E9bFo7a4g)@-RRDEe0|54S7`XJDcL_+lemDf5OAa^#q`58= zTdN3$hxEaX5SPjUMp1N_Dw=DL#JZ9q*u(KMoZ>SBwy?xtPeHygXqN-Rw}&x;2Q2*+ zEBgy@16FO{TP>*$aQQH5jL)-BL_<18rJrW0u(ykE0z%v17RHR1OJRC|b})<>L4GbI zo0e~-=vRhf`J~ewngZy&?@AE03I#W=q=>ek>vHw>-iyzMW<@%`=t93h57qla(gGs0 zES8A@s5GJ2D!Q-i(1}7=>A9*35)6PkSmx+3R!_pR(?zTQ@*wby_bg{)yzdc9M|OGIo4 z1?y6YjpR>uOb{lNzR)hub&RBsFs{CsVfY>Ps{Pab+=cOU%aoR0xE_J=?uYxOkzL1+ zO+|Pwh$htOISJQ3g?E=yBWUz0?&thj@u1(lV&en}n)VDeRR#xCaWI303LE7Mrx5^t zDEd7z*y|%*&@9;IL#jk*X<%b5V`U0;QY>2)Bw~Dt)1e_+oe(&K3vUKTAmHy8a1;mg zg)CtcHE5J)L&!f24+`1H$%{~aP~@#3|*@n#0$4E_i!T_>ai(d^{h%GrjzLB2PiAp9{BW;H%7 zfP#iKB49Y-?%f$bkX1mnaas8wX4CAyPWV0UdQWwcZrP-W*kMC7)OHt0*f$S7H5chk zuO(#$z;b!a&9^lzy3zCL)M=Ry)8K%q*Fh5Jlt@kr$d{ZEv?{W6C=wdjV2DaH3`HD0 z%m8GYzIzCuEieUkh#W^I|Bnz@VAkO*W70+gdQt_rF_XLUZx02rS(`c#m8eOh#ONr9H|moqKr@ZV}{2cF4=*e6UOs>9{0 zP50vGM9sxtc*@`VY8$kOR68SO7EnYpJngb{meOVCcS@H6IoKm)lWrLUf^dr`no!H5 z%k@uLrxHka>8Rh{pt0!ZH?x5I`j6OgtdD=2eo<9v|=*uVBhh;id$l55P8k(6z({an(4+02`XX;W_ z`cliRt2>$mYCpUWn{21ilEK&pKF1s$QjUAzPN?jV{;{A)1~EOL{ye~ACfkR6<;|#a zchBpnClaD7jnD7A27JFPDre~x)dW886e-GF-6&&U8pEv81>{GwX`=O?91a^UM8o(18lF@wr`V=wTVbT5Rj>%TVWz zjJ1>TmG0BI0}khHkW*#dQar}xG(2ml0w$VbkHtba4lnXW2LqtGh=n$^P@;HW_1VccLV(XAk)y>P@A3}Y2**#y3${yXx5f=;Y0v-rfF@L7ajHCdw=>#-2ngkM!c2G zQ>vTbLoXipO=dk4K47WADzjIWx9$_mrpAx!?S4s z5O3N?6Z3x*^7fRhMZyQcxDFXh`Q^=>Ntd0n5z)j0UbF`(++pCl(pK=){ZQHemZCC^ zD^px$IoV~;R~ZS_6P>6EFI5uj4?RBzfNT6)FSTj=v~Bw>R&R~>fDrN%NT}-;*>(2p zv>pCHcE2B9UgTHN>U(f;m*7x4e?#^BKNOz-6wraaAowfs(-6y&3b~l1!ws{vRyA7Yae}BFF19Hb#c^do1nW8v@C#rx|UcUB7uV3snhMuV&gRz&p4NrgI)gAPC8~G9SA) z<)Wa*lqB9Z7KY(5y=I_C$?iBHEkz69>Hb*z<8Jq^7m4ZP59icZ)1Rj3X9~_zw+f4Z zo5~>{EL@8Rx&%%a<}JN8Oul%@<|xUhmuB|9qzrMp*+skQ?LE z+fhMVC0{JBKKDT-AsiYprJowe8Ky$1W^Xz#$U)6eI-f%rmQE0Ds7z}$D4Kmpy^&t% zPwsS)0=ruJO3`O=L`V-UeFmA4cQH+Uxx)wc#riSLa7Khv736!m^6X#eYYPN-4mfN) zOn5o$cWNdx8cO%I^N;HxPtYOMZE|ESa`)@9Q2Q@z6A(4K^+QB_WC+i$0ez;tx zd$-FvjybK68De!l1+(Vov-YDf-{oiayOTR}pq@aKD)CvNnOMu@6O7*3-Q54oxw>JT zbZ=0jgrt@yj7~66814!d!TVA@EurIJZPZ?i^9HA7gmSJbg>(JK$N`vgJUSjIp3sWt zWPXoBZUIn037lHQC9iZ zT&f~$#kw}bWSh(CvT^5(sTx=-?UnW|LL*Z5jDzK>tn{64rzN?+4)eTDx(%wFybx*D zv4hXHBSNnP3AX26N@K7c7f;xalHNiFGUrM?>S(Xg>>Dhu(9x)hIDI9-pK+V-Q5ggI zMTuZ7_c`3Wj`3OMjq>7^vO%6WAADSrRa}f%Tu%30RVUjIre%-L+5h}71SEjFTS0fDbYu@Tt^_kMx8;uvk0`)h_n{LF<4{AR6FTUkneCwC^ zM`!VE%s1OF-0YCK`S|k9&MP;cJTEUTAbzgl?uJf1I|ck3WcYV;E9_@Sj}fl_2WN9m z(KEv$QyA_>C0%bZ!{7O7^5vo)`|+n=Zr+T$Z0=Sxc9{U_WDw>5gBDLXnEwM{{Q3O! z=FOE4vk%m4Z~79{5(jYLje$%7()Sxl2^mYcm0Zr*+eNQ07nzP9qyG?1MANh%Wb&7j zH?D9lc4IeM6T<=q8$ycSyA3@XPguV(`i}V@c=@l;_`grLcV=QJvu9kav)5v~F{GtO znaY!HF;?fVb-%|Hy@6g(F)K19@4i)s=H_H7*)Ui~aej^QB&ec8(St;KW~`Ziqtj3- zl5NlPIFwc#VF+2fPsFdAFts^*DYD6)>Ev9t9-;<=xd5& zkE=XH2cT%qFDC|mAuAL!g@Q2cY=(lmZ7Q=O43tU=uqMrhNg9#q4^A3&h{;~9bRREH zuW(iBr1NGA<$(3WFEsON%`}wuM%>!xhixMGyNx-Juy6aXM}SP_eQ~CvL>gCEhMGX^ z$kN>&m&?qOng8c%@}6OZTHJvpk=vLU!*j;Zi>IApXWEyNvuxXf;I|IzOE89F18)#| zPdRh(Oci}m2bjZG@?py;f%AhUuc}jliHKj9<_4$dX30k}h9pa+u>My5#)O}^N7i6t zM1rtM+@nm00#gtTaPSCO$i@Nym3Mvg4vwJ)i9~1s%gMRKx#&`6o(KI_85M= zQn|tyj-QY`25f8^E4|(Z7v>AjjqDh;{3k#&3DJWn*;qlx^Vp0+eDFB%~>LFIXZ}dHHDuYKd*Q5g}gH z(QH1+HLJ}GJEiDpMQfa8Ub;MaK8;>-raIqoXJ$wTLMG3b))qQ7hHsXP0*tD_M zWo`~l{&>B8Dw-hLPqqYNcY@@0)bwA57L=xf zgvGG_18tDVKDk@%q83{jnxgOl#%?&u<(Du6-Q3N?GsnXgUdn6P5K>jS^RI^_{z&>k zR?YRU1P*KpR$j!1*nFgaDRNdLiCW}g?0kYVDhIy^8R1O zZU(wCJ?Ghf_=M9Y@3wV}%f&r;2{}VmEJa+mb6fnjFV4; zPhcq!cdtYchIra$1+RsVq^d4#;K*bM(I!PXF@6LnDoUw=LoVM1qEDui29h2g0PID% zP${thEa&8PCk^Oph)$M`KNG*@wXt8~RAutZb809_ zej-cN!GSWyM7k|{e1U6LBt>4?DuHJW{d;Vu4Low=)_3rSk2oEQT-O%sjx1DSDvW9r zf(oX4=JwCbM^BiQB&5?!dQZ{Q*F{3|;50Hs0EUN0>##3g6HzGpXg1^gNZFO0%pQ3a zb*|t_INR1p`@LH;iBzjA>$j{|=-J4MDEg+*eGUY@x2c=t&X#DKbcNJN6!-b-&G3Q7 zM&ceaOiF-OOjE}s9yqijHje;{e_qO0i%|mk!_b|}DKvLIoz+55E?%R;%TaLln4!Z0 zK`ord`@^IN{)6&)BY)pNYWR>}vcM0rB!=g)fImI5b<++X@n~FTcn=m?j~`Zpm}n>S zPH8)u@tO_-$!8_YHzw)-JO^9(lv0JgM8}he*U*w+J>b?V_8AwS!1elyp?Ry z|7NGDDt~&Hz&1o4rgl$X)~A;KLx-JrY8tV>M}a{$HN35-SrKo4S?1lVdAuS~kC(+e zB~=p2Aa_3!@|J1o{Qn07Ad3qV+qg1SeD;W9P{-ujbFozA9#N~>;9-c86L~jDiRl^G zc5Q|uiJYuF(edKji3;+|S}479mD&8#odHglT3-~%IQHvO_x+ZGs552?Ekuyk+%3jVQa~Jc()|_Hs{R@w53$J&||(1HqbZ<~Eq_&Wg~n9G3j|kmH}Q+y6dsPgtdenl>0 z^v<9`J?MMO95pUdzkYqaQUl`z(i%X5?0mhFEalEXr!mZQ}(SD|l8a|QoA>txJ}!r5Bg zTi0tIv5oJNynhb&ej*pKREOd+SEhb1$vv(RSOsS-%{*EvdT4t+(B_@mwtPdxJ&)2i z_hZ3VP~>67_y227g4L-$AQs$Qt1e!GY@$Yy4k)ODqCS`9t;lKPiElDGG~VQU_pKbL zOcAJ5?hqq@U|$$FJ8bxVpAL}^4M<|V^@*VuYeYAh1jlO5zWGwoqbiI^Hi-jY?Pvl+ z0x8_9p(OtGnN(?%%-0>(TCNcoFwf?G7~FV*N8sOI7cs~^7>I7|E@ABmE=8T4+;B%4T$%cO zSE+Y!;}enZc!+CsP?0jM2+;uvmxd*=&GEd>s5S6o&w|J5UaF+Q{?VSns?2$Y)ZAfr zTy!oa5a6GvLgm9yZ-AsbST0nDB`5PtmIRif)ntd^ETn_Qto0|nU_mOfmR_|M z#7MKeIirIjpJREb@(Y99f=SXw7MT_>4#=rVZ-#F^WfAfev?fcg&Yd3 z4rKJiWDH|OHqR4JfUgG%xq*w^;1Yp~m3l^-Ij>n(U$oX|KLGv8o0AteP(T!mZ;h#u zYL);SoI|vTx=nFyoimAh<%puC3-p^BL+<~abp+NoaIoa{U3Zh_4<=)J0uFEP+Yq>r zkX1!a(~u+;6ePR-gB}j>|G0bapeEOTZ8U@sLQw*Q5!(wiVE zMRWxSy%zxiG4$T6fEapJs*2bsQUw7;M0Cjs`mT4m-(68&`KxHwy{I6Jzyc&xZwb#V<|am~g92rF)> zF7DYY?gcI$H%i|i9uN=Dg(yt!*PQiU6 ziGD1r7{sa`n0!@u6{}QwPhr(x7=O(~#KU^^x;p-b$Ety^Yd}k1K-g+vs%ud8YEXe| z@IY>$V`*@EsdK~X%@Gm(t0KMwt9oND-fvtzK8QH&mj(zg|H0lDAW%wpQu+rlHZ;=p zo+!${%Q<`iL@X#J^14N|gS@QWB0bh3uewDAuSJEqMaQm1r@F;tuf-I&#a67vHn_#L zuf_Ga#gDATPq`(`ttBkFC2p)GesoJZTuTDFC)2Mdv$&^lt)~dMr;4qo%DSg1uczVM z)AiQVP2BHTuitTW&+u5!xayu6ye?~wk&9l>0*C7&y0a2RMPVyrSj-V8u}2a_EnNjX z72TPi6v>@yEcd8$pfc-;=fkU21_tlzS%_V+ zqK~vpP@En`;HuUdP+RPKJy}n=gPvA;FS%DZW*%ZgqB|Gjy{v=R$$hUuV7303hqQe5 z5Sn`UB#|##l-xxmf2`20+kEoGLfTD2pQk6Q2KYk|^b{S=qa*qG`)0p|_eAQJ-q?m1 zCvj4s8dKEWQnE>|@#-GQy?u3SAeP7wFDm`&F_x$5Nz41$Mf=%|t@*`LOqsWi8-`0h zOkxKpd(b1sgJXVYja8~%;0==iXh>Iu@pX#f@ZLB)0Zzm%jjSWu$ofMBK2pU}Dvnh{x}Zu!9`{7OuOxU2>qh1Y1g_&gu%5ynm7%MGiJ>AxVHJ^K@H%lU3|lQLi6wqm z6VO=CtHDC9$W;M%xuiad)netPs@1nKZ2-Px+|pr~geCCQrsM)}YXOZ1IFb2%y$fq_ z=cY=gab$kZiac<5KX2bEZy)1WRUU88^Wcf6XffF;Pwau{L9hqdw_1u3a*ZCpg${qq z-q)b)fwCuj{!p7Wu=xO8A< zAgi{opBFLZT4gd!f>N(}G1mvRZ)Zqv79Qe0n|!Dds4GmYzyf@+2HoG$6(R;T8cu{q z>SChTvgyA8rHnSSQe~tLdUygWj@aVek*av0C4hl|;pD>r@%4otada@E$ahglx*z4U z3tKn5a2@`s2gcOLHeJEa3gUZT&Ue-WAt%M3vkONy(Ar%oL<2!aZf>XDT;@uzWxI&H zbzwo`L8NjaODc#jhHi+ex1bu!=-ZY}bpnCql9rHF^~9R(V#dg{ia-`iGUG&O#}Dxa zVFL2ed!BSMZ5u`=$sL8jzs~DJ#Jh8Lg81Ugf#YOa0s+oboAoA4cA$8j?|!2#J`OF z^rnH#7Zs{#(uhU4qT)pvIO{NNeJk_-BXG^AL)tkWOvYxFqRLXmsGAd zevNV*<*7n<6AqB+c7+KO$m|072QXZpkASB3Fw}3#FloY)8nWiLseG@??O+QZZ*Bqy zzbng#WjA5Qu-rEb>tf6GkRZ@^zl%)xO?0@#fsxmnCY?Z;GdV<>OFLL6f=t?VSlS*o zw=rvqpi1on{??2I+>nEyU66e)iqt1mKf6Y4b_FlN>~!RzY^hjl7C4a3-W%t&KP^neDu%NO;%%A2 zC>N&V+dRiwi0mMF9Dy9kfrka`W8=~HR=#xb5+euq-76)qLrS=rHrJ)L$M3dmme5!u zr7AI{60JswFKt*126QQ~?Zd2_Vh?RJ0b+^C@O%J4H3o8nJT&$(ol228ZMRkMNAR0% zx>?ud+^`P360!!TgOPpLMw^pgZec9XWCR3dT=|+gc#s9G#m+tmVgQ-(0UqFX8NGH> z0ya~*@jw{mV0~b&$5kR9W?7iXv1%>#GN3(HbO=q%Rs@0K%O!HZCdc8G6g3JBiB8+H zIMk;%KMt@k<-AJ8vcmGR`(Lu2DCK7=)*y+HFl;n_ow zXa-Q+Qi$EjTN2*_UzB#PMyajET}i72btxXboesf;gv8|BE@0{0QpA~YNxtE}rETbo zt&_Pfr53r(8L%xjF-W|}^aY!IQ_lVi=AcUh*1c(Sb0=1Gmzsh~4rMEJ6whOD5p=6C zuK`zw9*vXkcr&GbetcXP{l|tt1XXQVw?v41xvyh)ET0Vf3}?z^xg@^FRn~Wey9ZfL zaxbfXWpy*k*N9RYcRnuZ~< z;SZwM93>2i3~3x8ozmTis4lTiZ<`6$*Gw`gkH4Y>X8iNrc}7^6nek3?d~DXAmjD^zJKT|$&Xzld*%g0KqNEX!6D~}g!(Qi=HoeJtmkHd-})SP!v85q6P`k}C&>CDmvrAMEB7CM;4O#8g)BkCLcZFgAZ}g*9Lg?G2e2~C^keOUa>Ws#98S=^%BEaJ3XK+Z!F$$6 z9QZ=+Y9s@?Y2>n(G^tPOHx9+d|EQ=+Il-D`z%SVCIHij!E|L|PGN7L+#sc)Xd!O&QnuYw|CliRq3V#IOYu+NH%*f>9vK#d)Zo=F-lH% zr0VyalB3rE?6dXKCWw?(+bGfG); z-Q~|0sO!JOLCYp4Fl-;lKh#5=p%8F3;@LSCc))@h=FJu72E{iaU#g|^&-p2|kiJ;eMxEWRh9;>*+$mSeY-ZvG%EaK3ahXDCnQ<8XIGO4&A$?R?7Kd#a+r{! zA34+Ua0W~dVSG9%S3vzZSZ31OEq&(kN7>d-Le^m&k|C6?hLG#oxN4?Z)CWx5R|^1~J&x|TTBJZOZd*#f=QERLfK8Yz>$ z!02wN!Tkmr#mI;`8H7qdwGWNP_Pu0^u*4&I>+xp=7h^Igcqp2ga+3NYOcAUpcCnsl zv6;`#G1QL=W=7eY<#U>|0c3-B;u~}?4~(_-pu^k})D0YXymhoC-Y|!rYr4#~JF9(m z#U)Ai`x1g?UF$1NYI4jwP64(DIr7#iDH@@Uf;Ku@QUfWeOk+iYr2+%zKCYyl|2~22 z;JjnRzMQVDD^y_t@3F{Wj&cnVGIlwWswsqK$$T)gd^+fb{-qx*S>3P|=@=`6%e<_2 zhs{=G@4hf_RcFnfOka^Nw>sx}ku~SV%nJI!i*r|Qv*s?qR+WaW&im)F-di_YRetf} zd_Wg#-fsG;>bjNT%{Q#~zs{_xe|=&2$Noyf5o`@ZXKfVD3(Kc7U&F!m9$TYf1oj@3F`SPcMzP!BqcDOjC0`k;5g#}JjnR&h40?y3o3fI0o7w(~<|au{3zWPB3} zCng8Jm((=E{I))|Kq#P#>dar0s#8bm4u`Oc*$&m^_eMdHdbv9F1^scHavraSWE{en zRBGC~msa$cm`|Bj*bX-ok7i0=9?7+mq2^Lk@?XJU4lNnKj|rzgrPs7Ja4KMLCZ(X4 znuMT1)rk=O`ktQK$;rRvg)@C*6t(s?fI0N5#+htm{8&A$hdI#Mgj7?N6yj(qB zqjKw@iv8`AhaCZ7AvPUHk&-qoWT)-a<(5b#E5gmUOQZL<4`O*w)rhjT8Qn%Kyno7X zF?Ky-(se!*!gW23cFBBy(3v{F;hgFrB+J~5&ZTT2^0ZL%v#TD=0PUbB-b*k#efUaa zE{6b~vjpqj-QfsY?&i;T>DMVW%(fgZG`v3n@mMbo_)OB~NnPj2Nnz>g<+YgHYsqoF z6&$%;ki2BY+ zC6Fn>Gb~){#Wf<tGAdN7`2O!hes`(yO#7~2!&FA}hEb=q^R6F81PSthkas#&J= z6swu1&uiN;&zM{|!Ti+1^&#|`b%6K3+3zwSdVn0@)L;8OYrZ#8-0eeKO2d*ySm@9F zZtMt_50>?qi5AxAPeO=%Xe%sDgq`Ar1WxexpUhKH!Hs-B5GsU$sjqJEkmvOVq~yYJ zuZ&sxpA?=k?we#aT^nN*Oc2nFT`blvMX=hZ%QjaU%Cj;Fa_U=zzDVZVo9%wVCK_JM zCm;;fM~A-XpjT&Ep1V;2D}gdiRL5QDPI6?swXvpR9+f9f-G7qTCJR?T3X=)8kDsCD zRRq!)mV|HsD@L<~QU%FhQB-OHz-V5(Sq6_87KPR~>n{@49$epARJ+CP*C!sxzWrp~ za%6M9Ic|x!B5M2NBb7W>-qUK=WkcP!>d0>%lb30?oVTq%bb0gPtCKSSxFZ?VVFhXF zc-!cvon$tEdgT|T9Y&S;#xCsIg?M#=b>_i8?DCUo?f2k1bGQ0*2j}q$3w|^<+A=$t zyqE}dwr_y5W$s167k(ys;>|@Cro!N;0xNoUjd5*watbpqJf(=1_mrj?;#%M`rwNu; zsL4pf;htqyY%5(8zlDQUU?I@#eAKeGHG2l>8uOO_a%RelQowDe0#Vjfm+IBx9DQC$ zsJs8v*OiQx2pIJ5Si%hg10(_5|HYynJ19;$7kpZ1!C(?J;MJt5cI-(ekm_2pBklOT zQ;5rY-@}Y4?nuf1q`fcA631OkKr%kR5p^Esw?|G7B$ZE>(h9q9>durI!%nNEF%q)L7TKiXC$lmaiG%eOGN7D8Qhh9H#<-#qSU-F{0x4pg0OyGui9 z;+LLuKKQgcQK*0a{KNLo?`Io5j|0`0ZGqQ>BR<2fw!l!XCz+SVFSc@@pkgT!!942v z^V`9v_ix7^Jvur9fKl@V5W5>CPzjgKhcTkp=EI>{s0AX-!fhdf6MS$nRmFP-ThsPj&S+A zD9nwvcWFjiq6M&-K2|0Llg-s$q4qt27^d$sh>|Rm4EL40XFULgX>Kj+D>>i!!^U&3 znWSFgnSrLc<^{bQ1b`Tgps2gP>>g`5=SBk83gXp8Y19wL;On_obF00wqif~svi5Hj z*GOTq6KiEfEO*_?%SvLA3aL|YQH3vdM*?GceNK7_f_b;ODo7Rk8)<}>ZU0W&1k z1LC!WS5GK`YQKK2qNr|8#Iy14#Z=Gc{6$acuFt$xzO6~ID(kFYz9yGeZ``ncn>BO0 zeP`gc@YwEP*NEt8^&5*(t0jGVG50&*;hP_8c^^sm7aE!cITwHRezBbCkQmfGhDqb{ zpTIAPdrazZC|{d0P~6&^7DvZ`XUr~me}2kdknaLyn~(qe+&)UO<+h1gG6n$6LeOye zG;Qs_^c|G^^6J`i?=Pz4c9KNp`JpFC6>ABCht+v&gZy!3p zeE7CazJHO5#+3=Qv^ykH`~BmX;`aAX6WUUL?#*1d^5^GS*V;e#Uj=Oc`DH#z>c_#m z%qu^>u9eoRf2OASEu*gmDg({}#D7{S9fGF|_*{W)`PJp&jMLgZ@n8LfA19!%TpTNJ6d2F@l}i58LMdL@=pPnZhQ%A( z2#ZDch>TA4v+m>hY52}ZACP=Mo^SSi`o?0kcOD@Svb(d`%R!ePEkdBq;e-o*Q1DnQ zbLd#_rge{pTcFxxB+3Tv>hm@TUEhw`2wGOFZ1WBH^PM;%C*Ro3ETggkMvs z;cd-MY6tOoj>kzUcaL<*{n2#!`}Iv#2y$WN{RM^CH0&(ygu?y0$O+b&Xw8J1wD;~j zv%YZM?BAp+13+tlD1d=7pWi5@(*Z#%iC3N%BxZ|pwpI<9sgcNqASa6TL+vH5u|yk@ z5<_ztvpDBdx^5kw-?)jFC36@TtG_rj+lV7G@nKgChM>iI_f1d(xpbz&u>dy+^VE`` zD8D?2{k-W{)3;4Ap-vw6=wgikYJ6%p_Ohb7dje6@6^!;43&mLlm={2{Pt$-pzR&m( zR?+0Vm;;lF*R4rgJ^FI1BX>mU)~9p~{#3uG^wf3k)&&lidzDHh7nmG-gTFJI=fg(N zhMy+#$F5iyaZ&p+RzBC(Pcyel6-2U{+1l8!|3IW^8}c$CZO|c{7{^fn+gXSBhsoU$ zRKxc@pXb@xWB!ivf6vEb%6!-xb%)c^Gg9V5=bd@8XG^q1?m^Lo_G=IGB#P|omasrp z>NUEkM5i|2U>sN)R$HvE0fYzcWhLh;`7WL>=vXHfjNadsXU}y{?&-Ur60iu0I{ggq zfU%=zz|0_ZBA#amvx(HqnTM_yv>0fUJO*Q)r@!fp`7rk!;Lu;fK(4QtjHo52INkj8 z)UtR3+Re6Ib**3-*(42gEI z8`k`x&-2YkGEONY{&j@(lofBKj1YmTBay=)##dS0E8D|(zte{VB>6_4mo;gkc~C zg@Ktp%n$Ih8V=?(;NN`H@!P`s^z0bB%da;>0P z|AK^_8`y%!9a?xYkyqvRj7*A?ZbY=nMniF`2~{S$%vA1+`qJtgB`M*i&y%IvHj=vZ zY@DVphI+c%r%#XyQIGFQ6Xz!Lg1`_#w`9a~qB`nDgCGSE-A%wJW`wevi*vj`kHqS^F`{-m@iYFX6~T2TR|!7)z9=6 zp1)b@JIZX+|D0{{-z*hOvaeg{4n28_C4M%UzdsHp=|bVY@&{t+;g)!m^lx_X_wP^r zWe1@&tO5rA03~p?Lp$~wp;T0V@3#MWqIo>~Q~)N*>_Y%_5K0^Mzq%TRpRU)E@&W|r zwJFLCUm*JL0u?hNHuv>zF++O!`y!c)L6E&VB;JS!w7rU=PnR@0dGgYeIzw4B?8-pBB@O9aWRj72DT2m7Y(E)S>E!v*i?tQ9>;;Gs6E6E#6F+pYES zGv+kA;9JyRjF@x&R#qLq7}w7iE2O+wvaBSpy2piM6Q)YwRdZ972r0U9zbp2TSJG@v z5SowSr9K0fo)FMVGeO@5z*CF++&K+5a$1;A@Z*Bj7X^vJ7}Yq8%)sS3Bc`Dw-m@zX zgl)%(Ti+ttoy$c`@^nJ?Km>P|HT7%;Z;Quw@3`ugikP0>BkZjW@&QFhX4+&hgN5d| zBm~`{4t5b|hu%%54N?z3isq1Qlb)|5|9ivwm5BVW8&;WNMsb|TW=s#FpiGjL4bM+a z?vhW3e<3Vh&ihkr7p zayqp6l*1*8Iqe)fTEMWq_f+2Q&3w}iygX6_x3HO-7u5r^rxk#OBHw7><6FzmYH3Y6 zMmeu2JboaWtDca(B-`4Rj})=oXuCWYcNRYL@LQq%TKGLqCB{Ygx7Qx(0H)23T-hO= zswIIYe_QmHDnuxN?<;Zc8DLQeMwFZ}`V_;|w!E4dtjRoYAIA23R`;J;*75E@{oEbT zD7$0lmv5o$4pfA7XW(>^L~a>%illk;HPjxnNYY@Ux-fl6k>T5})I(loXp9zzq+Pq? zI!;d7a8OC{lb};{L#cWU!}ZR1I@6LwNwojsD_Os6!}KQ>VtBk+W_3aOtJzn<(+Osw zyLlP$in|r&S#I9${dZ?do<}(Jr`oycyUb;^B#Si=%e@Ynw_-qzDmct;h;gGWoUI)?z9;4}AFA6|~d+(pq0Hxdh z{P%JBI1_tH8LB-dA3<{*Js1UI=VXnsFujll2|HB>Ll}#^WpXG!G@v4;>PB_;y(B8= zLR>2gUzZM0@#-c@CVD7!t<0`t<+9^whJ@VJJ)>k4O-wO^s zC+>sv6HXIK3#ASte0Z8K+k@?47KSiyLD9-;7kyikudQW zm}}kwKs?`S!T-hNf90G*l#wDZ$;TN8bqJ-y!}DdYrhN*~^tRAGFKnAJ+UEYzi&c${joUPbZC)0NiGlwYwnywAhD z!3<|{8d7D14ww$#aRz{mPUsc?!wCrXwKlx(x^<~nOO3NhVzNnl6>OB9_Fld8Dr<0= zp2E8%qRHXLyRY&teMx4chZEvZA=6A+ha0eia06boAfFq#mNI~W$7M_uw?KBH^i zIClA%p9RVX!0!c0)~^CZ{kTBUj6N<joqu56|51Tb$p$x?)$4YK8qZ|J&^wxmKd)xQzbPMRnQQjA5luOD{h2+q z<;tXS$BoB>6OFtr;1c^fn9W1)$yHT8dR_9)P&Qro<=?3a%{O1fmXMf zl~nNZd41avG2^w;PP5(hQ0v^bLW9O?s(MxwTDddGa#Sq`?eLGKo=1hQW-$C~9`wtl zhyMHZg)ry|CL58Cm(_u?tYmTw3+wHPwiH2pGCy+xKVHXhAcHs&g4bov=S_gixQz7@ zO0YSC|0oLXqF8HS8&hru_s=o~55>qWF@?&DgWIA_%aXEn3N5~4g_H7Bq0JTNhUR+! zNwn0z<%-Ag{#UqFJ+`lTDjIqwMi70KeH}kNJqWCPEvs%GAI=N3y{2P-xfj4L<>E9i z;{c%N5JmC0F+23#0XcTTeve%LZzmArbpMh-{Fh$yS862jmn#Vc(s4-)+0XYx&@%)l zAJi@O#K5Gji8?Y!jVLx|t)dBO%x}5XvD^Li03783f4N=o4zq}1UZh_LBN4L8-yL;B zT3zCx?s9G}0q`4y??s&@w?# z(}U|mO_4=PQNIVq{f+HL9n2(6P5U;z*q%djrm?uirxas;?OY|fIc$5QD{lgKr5K}Q z99Od;YO>_ktio^U(XrLa{IuG&->p^<<$KIfQOn0u7%F@mC;$1eq22j`M1)i%&sRUE zfmC710s~z?A^ilYGwtyYe1#tq(O3Qg{(dr4|Fl|BL(!SV{z73*2e61ui&8n6g}JNN zUi1zTTT*4kDO@~1{pHTq^9mZd_>6;c4h+Di-@sNflt$te&$+RpQ8 z<;&Jzs3(Pa5W0|x#;>tZhqcjcZWjH86Npu4?V?tNOBrw7uup1 zz3}!I>M6+vB@pONMg5I>=Ii^|Qs_CJ8=My-f$o5UsGq23%7c6?fG%2x949@1TKYGr z=h{*d1}yp;>X~YQUjK=DE~l$j3>Czgxs)$w*xp!Q&a{sdUCDAfMm?1(vM_NzBns;3 zJ0QB6d+nL~>b=0z<-$2Z`|GRs31G1`5|O=PInR=-f`WRYH`WT1wLAn1y!9ybT$W44 zdP%N{u6rqoa{5YHQHIA_X-P@NMnzT2hFEIZ#u18=;sT`KSGKKGyszm5bG=VsoDr+4 zW8CxDtRG@=?`9eHiJ=^`|HB$t-D{yAn#fP!2RG^y{08V_BYm~twoZDQaF1NX8a?+= zU|7q!JyAT|8Pe^{z86VAQf?#c-b~@n^#gMnE0bv;G}6jF46=>@FsDc0nJW*Kz^cCS zG!j&jcUfQFEbIrBmUm~z%vnkTnw4a|5>IMSbb8YC-O{7;J!=4N?#ujIcliZnE(2VR zn4JJh(ad`gDQhy3(^-0foFwk+2j5YykWZ+VcPo_MKV(WMjjG7Ha;px-@fA zTKQT)!$|uku9rR0*vHy6JGJp__}oI83;y}rDS?ASk(~DS_1GS?_74GSE21!nGRY)-gaX_NSI103;m`BFPvqy(&TH9u+uPn;?_$rK@ zHQ^_YB4qE)!Dum-Y> z222*%3o=GiQGaBm{xc9p=2#%nEgw#T$pm>CGjF2MCf6ctwUO@y(;tUO49$)GLMXvr zn;YT~k1zuNpjxL{o1UaQdIm;r3F%&wze+gpf&rv+NdWdfQi}2r_IY!NBB|fc$k774#=wb{R|rhc6W)Xv~)3auaCF_`LR+T;`Li;37y_J`nej zpUM|Av~cU=HM3~k;8wH3z0k+S?KQLvc3A5jT{Wq+2XG0U7xr)25Gy0(fLH_p$r ze204hBt`bgIMC?20ok&KBQ6STIqRFg-hrGs1FQnj>PEkoKqeFQg{kh;T8&wQ@&?s5to)-widiTA4r#G z_Yp#02u#Nos|LH_o#jX1>(jv=AP@e_N)yWo@rH_A&!o)u8P%SRXwkI2n{iZD-DJZ6 zrKrPy#6t>C$n(>2TXxgU0^}G3y=Y{-3%j&@!DHCr`%OP|?NSnbGzso&n1}F^Yt&sMUJrgFApz*EoS}705a8uI97X zu4?`uOP(7k*YI1+lhQHBrJgc6ez(i@x8DJTi{!Og6PRrrn!;Xz?OR*Ut<#}1+JJ~p zn!`e5hM@{P{OJY6ftm!Bx+fL7iGkWV&=@pAs)dAnB7fQ9V!OXm_rAwiYh~H^=3CFg zzNwQP%@GxbXBfduQJGp}X_Iw%4xscPHUN{C+gKR`a;(d(3k2zY;Y$WFq&sx5D`^NI zMIwik%R6jCtYU-GC*TTJI>b|{%Ohm4iC&8qGbhKxE{0H{qyh~ zpqOjK%~?WLdWhqMEOYqxm0kxD&@0dfM!xQfVL{MUr#CFrXakyi)@WX82ynmfz2I(* z&XaL;P9Co+1m9P3Pk(lr;g9rXF7wY?tc4uQ5|{}5Xf(t5$Z9To;d5rw`cIerukG&} z01$j1a&Rq@O@#NS&*~kztcky_41K7^4{c}#CD)|?@yeC6`>^;#aRGTssL*s2@(8VW z9gb4$;T%~TdBxBiYuD;M67*6_CNah0C4f+KGA;@IQQ=xWZ75SD>>5VBn?(>xgMZ@R zZQvHRoT@cpeRMr-X>3*eN|F7`#YXM;6RAx62+%2wfW>dnNwT(qnDs`b&r}po;uQ=N_M` zQt)ogDctt^bk&4_{o@x*E)>$ekdeF{xFhp@NWJ1KKuvOtz0N9R|>Kw*#LCem71m2T9JscJKD$3M~40aK6KoWhQ5z#=)CZTBgkHCZ>Eqcu$m8(Fgd6>!b6jTasYH7?$MS}n>X9C7E*@3#rFCo$A_VC7iT2Wt&rToGCMgTS= zG__T7qBg)2MpeD9CDlTe+k*U-g>*=dR;088aVl~j?aPYa)#Ttr+8hWxnU1I&44w=) z9T7pr{uERiZCqD)I{wDR!;cC_NYJ4p7MH9K_<9ps>MotCVmIt5-xKFZ0-Noe)0>uh z^hqGN6lq)trf##RTz+cPA}OAA>&zlRu?Tso5bQ9m0Ik#U%g|Zvp;3^-`B)ilhtb$J z$_x>ua69h$n9~#5y6=F>Qugw`pMv)<;C(b`AfIG)0V+6qr86-3Mzc%C6B=v&z}M*t zMp5V(8ss6ZAvZLWO@k&koZ4^t>I1kUla88gYsQ(Wj4QeTt2QLUDD=z}h_sY?7aeh? zfhzMxV$Sp#gLQo99b-o$r#q|xL>QGZna201EN+Ep;|Qf0c>r`KSz$%qFi$4tDm~UX)WzrR-Az6!nkR7q-zk^eK_Zj@HCHi_sLmAKccx3OZt}< z6`v_J>nS_?>)`K7g8H-hDzf%?$IQo$$dJ;^xdS&TUBO2|NW$lQ4PcT!kgDFQ;4rH| zHAW`fLRe4_DJzCN`&ED%D)FTx%2~kMjB=wT0vzOm)F~G<6cbz%5*#lIMYkhUOOW3M zz!PVXrrCnZ8V+C6LtW=(G&N-MKG|_M$mCMsB#IV-oS=r^;?d7+xmggRp zlej7hMuhT|D@uYZ%CaleO)4tpDrycZ3P&pHlq;L8E91o~Te2(L+bi3`P;TT(GFMek zwz!+GIU9neH@j-2z3QF-O$R3cY7aCafPIXrp9NRXW>?R(SHGI8esfqo&sDRiT=UMl zW+k|0ExTr;y=HT+=EGsl4p;3*<=Q>#+Wp|#gY4Qjv0xK>AT${u0i=SHs6aM#;G1=j zoI3iBI>wiEC%@G}x$9X}>R~qZ>^JKUmz)^M0#Ga5o63Gzi)>2;Xc#eXC=` zPytk+o*x^exf^9w8s%*o(b6{?m2w)DI~rAAHmZMX#Bev^RGRQMOoRB#dQQH-m0T=dPR3eVTc`$wGgwz7kh&Zx}07Ik9OaqFrm;yT7|6 z0%ph@PIzyDc-p8Qw)fQYlQk~V&~VWox9c?t2;!U`qYiW|suQD&#~YiMkP$7>#^2r% zKMaY?@KWH*Z0G(sb@|gUyPV?fw_X2=W&CHzG~mBPrehch|7~PiSU{j+)WTTL$IIj4 zx{G6HsSq{P(ydu+tg)qG(ZHkeJ-+U+FZE6gxGzV&VwQZ~S(J zjx6kNemk}}?wOV%P{g7tP$vImBDd+ll#K5?$~}O{;u&ZC%*Q%Z^lgGMyKLGv551l> z-SIEgj8}-5EBabdY@9_U5M&lSy?(w-#NFhn3|Y)Dp6V6kgon7{^JE&PFg7I&t&mL% z%Fj-p1Bom99eDp+3vh{|+-JntQ$*%4qqT|9upTTBisa>4>yGM=;{|KIvV<=5C#mzW zyo2}&&?j>k#|yrgB%MrWzg{JHW>?7IuAE{vab3gtdp(F1?~&-oGb8;If_?M5?eYAAV7YO*Iw_>SSk6-y{{g{LhcFKN3F^iR8=4rD%R1^O zOI$h~FDl3XIGfk+KZan}r+(9M<*tz?C=hJmrQL-%{5&Z}#BI7j>8qfZWt};LiH`mk zy64G#Z(?cmACr>W-ESouv_ALl45X%4riy6!f&#$zv%gYsuk{{cK(uu5sHr4o$h0H2a|+Qxs8`Grq{c3w%92BOj_9hhA%A) zr0KROe+TpVoM$=on7Ma!6e0?fg_4d%V9UGHeaEt}_(A)8iu~VUV61nZWvHGa2`UhS zUeas+wqJi;-^{Q`H3hg%N4O?&G3gwK`k!}iP~>G6CtS_Pu9M1=^{_%tI`A@B7nN#X z1ox*Xj4U5EqPaQ336N&Y_u@9)^SY!6(AiTw-W?0Q(JeIp(1)RQwG7Xzoe5{4E}^9e zHvZXO^m|nJ->3AbIL&tELxI#0_>1NpE^!p`;lruo_n$#RG&Q~*0yC^9?OyvX>>=b~ zwY8Tt)Hr0LxxaW~1s2IMy>X}OS;Gy#>m@#Ce`nESE6N%2w5{IJcg+zFL%*o4OUYVt z>D+(NsO0xlwnY53qTM{Pe1WTT<&2->wdYRLiJ3m{Ue07QbOA4X30S;P7^urr_d zaiXFZC~WTzMQ?V@_EI0Sz0lI?Uu-Wo^9CK=N90eoSAY1rvntq#4wuVi@@t!fMjJXm zzxAyvG9g&H%&Nd6N!V`W`u*t#P&Kn+`j6UuxmSYJBZeoD=8ft~V5Q-v}1rbF7cZ6~n(PRRZu zc#J85`)5#2_Ap3y`eNRmXe@APHbqD{v~VwDVpWo zdeKOVQpGMgJ-%#Gaom3udrH5BB5P+W|0vN$^WLJ`X5v`Z{TGLR9zB+|8`RYshIzkrOc;IeQ`TPDvi`#3S*zWJU$XY6 zA%Dc44*n%;zh6vmA~-zT^PkJw=X>LhW$m3`KdntyUK;Ou`0dM2g6DrCYd`M4;<@o3 z$l59WSN}7D$4ptr>W(E>P%-#|%er&2j~f&Nv<-Gyx$9O^zLM>AENlOb;8`hO%?tSl z!Gp?mNVHlZMGOB;@QAG!rCV^hXVE3EM;7Pa*jWE3!Q+va=c@a$9iuddCti`MnAdr}A<;mRsf&*}G@jT2hpTTM-9{jKI%m&&b{S99)?*+2+| z8d|vF`QgD@N#%#ix4{GCww<0)ayzB}sy3Hh!tY7}=lr~9M@S6!HW@~O134YnIzW_u zD|;W1N4jw&&47tLw)2Nwz#zM37C`D8|B`Ju!HAJe?7JyE4uwKPwQ*}9&Aq&5 z$XZjD(UYDa=Q6ekF1pSKKn_>mlzKy@Xg@F;vgs@3@|nt`uVGwj3@HkRxV`F9sQP_= zt+)KXULvfKH(|gbSD)nm*PLy`H2o?`f385-<3cq6r?wYyo*&F<>E$c8sV0-G38CI|r($(X z?Vr~)PABNrDk}t?+xdS8XZq9(!5uka5v3VsBb&(9vNiF4y9%f>4{j} zqW3ln#lQeT)culBgV$pAJF-2BdAkXR3GZ+J$;!Xb`HY#t zp2|TNNfuekh)A?Y&^r>y5F!~o^$_4-Nk)Lnc7Ue|`Jsh4`$4lZT?K3vQ0;+0?rpkK zj=*F<#(Uj`IS^IfvSdVV6W~=JnPx$gaMKoJ1!_xnJ`h$g z7A6`!Nd$rJ|(O@qXjlNCBqjCwla(-Szb~NL*|vQ*)p;(HzDC zrS}YWmUKIB8#lXJUbRgSB}gv0Oeb!RyRl4gaVnv-lDtTCy0c{Z^W?~Ct9cjkx^kKs zOapW7!j0l7A;WBFSoagpb3L1M<_oYFituR>T@s2aV_lfhm!HmjFP{G9R8O9K_a(+< z9?%mg&CL}_zWd~at1bM#CfC{4>=;Nd)a(=`F8W%nRKAh)Z=Ug zy{iQiKVQw?*nl4kTnUFHxv+kIQKzzd$#mWYqGTeSY+^kTaAj;*QL8}upYO?FyF=_4 zT=vOx^tJPew_QxGs7~njcO=aihjTnToc!`V51wpy>1lIW-)>6(o8QD(9`sqhR${#u=B2vuvgn zG>WF9B}sm86DELL<^J1c)89KH_Zugna~aHUt%CRS|=r_^Pdygh{|+FEB`avZ=1Mqb23xs3xfs{@yc~I(lwqO5oj7- zyL@Y`BV}%UoU#p)RU*8A)8;LrpO!D@h=2zDb_^{?qYhmH2^)4p>ep2BOSBStZbjrD z%3VpzRw{`#BkzwCbgbV$g!wM{7T90?klJ_Q8IBayLD*Gm3aOfQPsbf|hjB!(F_no2 zix5A0pYts^-7%wZHk94O0$gkITcy+v< z-@kpf+={OaYDH9QekB*9q|z39yII-e=BQe)+l}39j~Bv$cXBTtRgsPL*xfM&ZWqw*CYAo9LYJpX;tiB_!a4{hnbvb%etuPU#n@yx-pjf98mXk9b_KKf)eYAbqlGJM(x`4zzuk2ou1!_#vG?dcZ|TUM8X5};Y{J$ z2{u5gj*e26dev7YW*R`qc4U1N%4{9)G;6IwLp*TTB3l28&6tVCdj?%MhTZZZ#(K%d zo!7Ovo+li??is{-*|AR7X-s%9UzmG@#dt27HzVOPTVM!M?tGTVRTcx~6;ZVJa&A`)LHgW*OF;aWewX=qabyGL*q5rtCMKrTaj6}+7Gin}oh;XnL zOf_q6_D8{Quj90Z5UT8H{;Xl_B5tqs0eTu-&_gfVQ+V;7+}lUFcf{19bbMWRi;{LY zqqZ=oP=51|#9X$-58iP~h$d4q?J38Zp<#2v28L&BYK4+lzQwZ z1w$dhJ<>k=r3~|!?i`Dxp)!)oowF7tyt2SKk8@`^#fl$`zneSzv6j6wM#QYz+(9AA zTN{4kMdEmcyN9I`y_;}yj0iqat}EfrV=HA>fWmSl%q^p-UMqqjS{)shFMSQU0k0&` zQwP`s0Aw#U3k%V^LoCU4$uAb_QbW#Ik{~GXKQW9z#=ij1zZPHq1MsLdRN4I};A!Y> zX!AH{j_LZ}7mwg#k!bApoXBxF}6y{{}ph3r$l;P19V>&()e| z?f#zu&vQEnt4uvzhS+}vJV(8Ee=pqqdvq7zZiTA1{vQC(u^RYaCD8v?Cj1Yb@?XlW z!oTj|G%8su0)iuwi4m(>k!W6hNn9JhUL5X>(i;y_6k0d zvWz+yIXNR`oFklaqCb)$~-m_pG1p?*y)+%DDG$b^YN zjE>M|PU}*ehHy{V3^SoKhF2owtrYlZ1jJ8d1bcqG*rQ>{D4W9+1>-Gi^p8{niowax za%@fBxh_tII};TcNtiV{z744{$$WlV*<~<=upSVFbM)rfyU3JE2i?hQOFIW}FtW|m zV6KgaZUOG17JDT`i@FTJi14jO--^zO#$_O}aghX1Hgt)&?l291ehc;=R~i``ZzRJo zk)6O4Zb^B>miJHSPn7N&QMjUxUyDAq%E}})8j%HHV%*a~4($La3(OXeV2AL~^x`y8 zHq(fyl2{CzcD9oCEsV=0B7{J_gkiSAxkGNU>1lDmY$Us{=;7iGEU>1CR^2k*;MeJy zn38Zk*aN*i48oZlUW4QQ8NwLM8{VSWgBJs-8S^TbZ>2x-l0RT>fl~z}I+H^d&$g4w{)PP6<8uhx&tlpuR zsJ4Z*5K7`g2wmMC;SU3bXPgQ;DMEMwQMXCo;|T0qAbW#qCuNp@*5*M(TrI2m>520Yk5MoHT` z1Mf*Ku+@o}0lHOcem@%V7{LuyB*fxOgLSC&5v;@HVQU_gc0t*GHa`KTs;AG2$J(jn}C$q-(sH%8h^&;Kn ztp-oux*P2CDMS30k0KNZu=I?gpBvnVKwz{8dYAuN(4gpl0|(=Y9G91w&RHkwc< zXc}8)YM)4%OcOwh({W4IjK%5_CH(yPVY&GJxLv~}sNqQ^U^;gMh2Z8j$1YnURCkI0 zb53uFtMZ?y2!__dIEz*z)lIf=!P`vvf1E6VR^{V#4&swb=bUs7t(UJ^Fm` zs_hD#^g1X(hc{3xJDM!bj=;y$d^XkS*DR+0nA+Y(8Ec8#rORt>RJhuZYRoRCJL~V1 z7fM=KatvFg4{vbz0Ot!>d@>2+&E z^BEU#<_hYiTgD&HXloFJir+!b#aKGEp;bAdMIF#h3c<-@kw&`H9xbfksaUA* znhsz6IT@rM-YOmw)SEzuzFY-7kkBf(8n;voU!^!qv$1RTLZ7*5Y20tdavSNNj|}4I z^O_MjeNk~}hI6Ce_N3~U4s2l}l^agRNI8i`UY7NEO~~N!>!Z2y977MXcvUZH&W`l8 zGc&h;V~ywj6F@lC0!WeTo*n}`HN?NHTHO~=EVtI#6|3Z7J>FxDTwXeHG!=f36y?u^ zjbJ0cAn-gQZV6umllS!Gpc!l7=%Mil50-#$i_b}nG}_>_V#lQHtkOR`n-SDm4}&Ys zUimV^NHUwEH47s#<_!tiG<8g6juGaTnq5DwESUL|Yu7(7{|&c};A8a~?&#|48}cL( zs3~>hLfjZkv0G0=0&YvRwooxK&b^{v;a&Cdnr+=K|U3?~U;4qlC2&v{LDC)H!SD*wfjb3qv=B z`a^%J1Cl&i5Y}C&?5Arxra#?UPVWz3x*iauX+O;m*vW~-cuGdmEF&UphIXUDK=~@fe48PH(}e|Mt*VX&tIQya_0RY@-3#=a|(=vT7|1$ zP5Tx0h%F)|^FtOlNmOrID#Lr`!Nt-@wUBJr;_*98ANUO8b=ddy#;n7vf2ldJ2$puU zBLK{y1P|99R4dC*N*i90$B%)@#48!ZE2#)X#bOO*;;|Nh z`*HdWp4Iqt1I)D!OjKP|^d6XO0LF^4?ra7YAu&0k*kep0vuykqfdnqu_&Q}Q7=A7; zKLO{I2$@b$^@nzNfK5ofJzdsrTvDw8&^&hX4q$FpiYYy*cPzfGE_q@sp=dkV(T3%h zzgee25^hCz&?70fJ7L}cvy^`;(jy6qQRt4wF3ly=wlU+PDboh=cucCzmCJ!`rzc@) zFn>Lkj8y1g+D|zier#+^E@$5!j;$hPu{(jg^)&KH9EM_k;DP-cl)^ug`XN7^qX%GLkkt zFv_;^EU47U{0vYw`-4H&GaF1te6~?Rh5~1{BxkCCOagi^%fuEuXPZS-1uq5Xd@;yy zFwDjbW?S#%IL&9}tsxpF;ezw>hx3vyqJ=H1Ru4O7j%ewbQr zlX=H5|7PYSL6tVUB9*#CD;IZT7Wx&IN^O_6`GF6Ly8Wy)dDf^R9SXrNXP*)lxM!hLk_{p=R zx;}5Fpm?P|cV;Jh?U2g0Q~V57K8;I$v{TH@P%ycZ#pabe_N2tZwgQLBdyFc+%~_^g zkXnXSRbRoyQ1q+5EGal2P%FMAMjcfx((|e+5-ZcGFRZey z%s8z2U|T7aSUP)HqOMkDB%U&OSXo(LeLA9?lZ!erPyO4I6YW_gG*e~3knfh5D;Zp6 zzfegOuk9JII$p?sdRRWGTHst*5))D? zbyOS5P{AZ#Rxn=A>RIl*knQ-s65>_rvw(3CuMZ5VF%vKGH>}PP&k$#5SUf4E=PJ@+ zs8w1h?oG({3u$y`XtW%!kP&YxU8vSbtcxG7s5Z1{eNDt*OO7o1p@a8$Rc)_T*Z z?M6eJXJRY;uX>CzwbP)TuD719p?#&H>6v(guWbpZef7aH7xwc}TTgIl=iyyp<9iJu z<@Q{S4k7Ke3?-ryjSt0Z<-OZ5-t`*Xo!eYBq@;S(cmb-YGsmk+HZ{59_)E&Oq-KolYnX~7{VV*ap+q?cQ?WjAFyF639H*vf=A*sP` zqARqhOJcC6YJx@U!M#RrmbS)9-}gP*tG#z0Jm_m=>0Nw4|g%XzjDkyu%px@SFX^AGaPJ7-Nt#QepWI|NeRi@X+4e@+r0OgWjeg9r}nFG(IQR zx9WnW5WuuemqcK*+H+V=lJ%1focP6N#MbBP&+gfVy{2X0FU#>go`cZFc?W}Y66uSL zz$MP8Dp(8|cb&aG!=F89q2}}`J>!w!Dkn9<2h`%K$uMGZA`tmcACL7#&4TDP9hVHA zt6kjvGq)dWjhuG}rB^P)IK1`4M>!cIGAAJRoTQ}U2x6D;Q?N3l;&?~P5KILCh)<7TEX z{%7Vhg>Pj)UFHug5|sK~9M9!1wbL$D`&-I*NSU1|{lh}r%3tNzb7^o_8p3j(q-9v0 zCG$apy`4utEDCe&p3rNaY0i6?!P`-Y#Kc8k5oS9I^UT2{9#gR@r!D`c#|xM6qc@ z08}iLr!Puk$3d_beXf?g_YV_CD>RA+C*Q$_r zWz#e??!DkD3sCPf3HAQu{jk!#baHM);1zD~;`jxlDY~-`B-3vCbFWw+qMep?!)KT2 zGzE1vZLVwXLK{Vj5}F{wvbj3 z^2JK~MZA!u+Z&K&Q$}qkumv%hI*OR;CtF!r%KE8W*}Q@In=-!;bjvkwlGVNw;Mrtl zrf|;{hS_{^&z!Pm{&kx~Hxk9m=75axVjm>AV>a-q4%m@*<&v*RLKkb7lumEnRAa{2 zgl`NgUR+eXVE=cfp-)Mc&7nM(L+Mxu3{5e=JavI?^#ak=O}q1@THs^%AjIj9bEG#{ zZ#i0qI&NM3Zs9fXvb67_lj#}&SUX>I662Hh?6l7MWK9ve^lO%nn|vuKCP=q){c^oxoy*^BFz_2>FZyk^Aw)YH z@A}2_?_wM)wf#S`Nxsqiw7G!HEd!$(-@;2O0K|CaRZv;nP zxpQ)QC{VfhKz2I2wpZW>e;0QaLI@7?WYQ^u&r@KQB>RkOv&yxq^ZQ<=o73M5Uej)` z@4JTzx(D2#gtRE>n!m@u`MAS$4W&JN+Pv8;J)gD+B){{x3Hg>|<>4L$2}^tHS#0LU zek0|Nep&3o)ohN+n(e{o2cD8=Yvfa!^nFy}7D949oj>Nf5ts|lIO56hn;vW!yl>hR{N)Yb`B!{z-uX(v{Z4|SWXdmZi$xb@(9J#Y zXYN&|eLsU*5ykb-{#AkO$GiR~I7s^Aje-oejLeVB<}fK@mbLq>`oDq)RA>%BxmDw72T_rr7O{6G# zju|n5BCMboFpuCmkhM=s4}V^MC;0w@ww&3er=+KP19LA)!Nz!=DKb&w&p}c$x-vUN zD@ATN-nlI+TBg1~3PEZXQ=AGqBY>I=(O3 zO@%5-Tp~k7oae&Ww%o++sCxJnet=>A7b4u0-sR#eOkFfKAA6=*nGa{Z_jHw)eVg^f?AR6$GnHDuPu06J&r&y($aN~Y`QeaaCLnwRHyv~(1nxKQ zYJZp#JWJ9VRTW{LpjuJ=&*vC*`gHQzEkegz+wGFBMBZE}m#@%HmcPbKJ>E_vAnv~_ zydDx#e(vHU?PNKdZ#|n|qCfY3=o)rwo0VVIq%;5Mr6Jb4+Pl0mNWCtMkJOzQRda5f zaI^V93$)~Z)B1Q|VXf~)7>%BTx8#@AZp4yb+#dYsRxj6DbRJ^ASlSYc(A5 z{c-;}T79_rs4VBt_ZMx#OPlk0cW>T2V7hd)g8^?8es~jjw{Uv_^>FcKt-18l<*mC) ze}k5bzVz=tN|Rm)slIpfZ1DP>GR?zUr#Q}^iG!_mv9e4iIB9g83IFMEQ=lsRuQ z67o|XHf0_vXi|2_+}-i3lPMJXoBFASLw;q?{0d)m*{{#92X~h!p_ANB&~kT8{x#`4 zFJIu%A|6`%Y#AXN>!n9D4s`;%e}t4n87cv%j(5(8c$&q}vMSQQrZp36B#6hk<3{NV z)1$2&mN`a#Y7foKq+*KshrL8~-hQW~1%7k-8<4Nhpot0pC*YrN9Ui)$0!gVn(N4E0 zb3~>0Q)xY41&*Nxk43Iw;wdgG`_o$^&xJCwR=t(rEa;Re#O8Dzf6e^}-8pAs zy&r03ymK1*e@ ziIbG_!A$zV_1vLsPLoT$7J|K)DvlHp#>)xQ?l)#*h0&tw!Khj9UimtYsx5{qoDaSE zE|v~@*BO66j(zJV6)n7RmXlC>Zl;f+`o9sAY+QJJeLOpdoa_O*C%&YlUX1>p^p0VE zYm|qft@zj1Rj!Hosg=u=>Y8G_Y<;(B1EQ_r;stN}hh8>qMp?~2hMkUW&=MB*`W>Z_ zvrgjY$86}rI+_!g#Cwsy%sa|SwIS8smQe}TbqlN|mv}#rzaA~TzGht(tKjSH?QL$i zA6Vx0$rlosV7fH^tjnnLgOJmM#qiwpin2f-7rGA)mBMC?EAFQuBe!5s5_MQ8m47u#C zZJ3|s-s^uL%D99;Q;OaxHS_e7%q`OmN~~g^(*ZR9(P@N#yq<oVg`Z=7?7aT9%$(ys7h&c3C+2>q zxTqSg;+N*fFTHBZhFe0!$nz8bAgy93vjc!K5vGwW&&7bqn?jQoF@UtG;91GKN`T-Se{T}+t3o~i40VOkdI16n9K!p<#3ay@I zHy2)%Ap-04&U#tqEzH*H2R2;n_p-jf@bYeKV3X@vZ@bqEukMcqwgmQjJN{gF{ZJ_o zE}9O+3=2aZ>)&Y4>GyF{UYvgxd!wWJtgqLl#f8_SH@Z6eef@4OF1|(F>>fGmcP(%6 z&6fVn-k1G;UXN?$KF8kd+dO+UjaB3mO*U+pRZwv&Qi_XjE~)KlSFD_0#mhV|tp`GT*8T{J)~e|1Dnr|Nh|r z7=yVCaXjI;SN@aZ2AnjM{A|~jm>1b817?hj9ti~WEk-#_ zO^7p$WEe2Y$YL>b8Bh_;hs6t=SuG)oscsph4v1I|n zya#_#!E&82&Ovgn+zcrm6dA9fF9=~bOy`VD$7LVyK?@|Rj?zyuk1B&Gf?S*yyFwTH zM;-2HP74+vxjpS<4n3!jT1sl)wApb)gAx5VzW6}~*K}1(B^-r;0Z20Z&|91wQo_oK!yn-rx7M`w-9Xou z`cT)EoQE)ags_X5GLClY<~J6&WO@RFLDHMZleVBc&1V#B$!08d)dGD2$PMtSLVukznCnSbF7yBj}g%JqZ7d55f1Qc0i@3x~ zSFpDKf}0-ClJ`s-|M>HTA`33T9F|}q*n_Q36F%J{#dYCUOHz? z>@9dfX}2)tIQD@l5$*LJt0n1%ZGGA*^e)=q8!IayZngn`-5Ve8b`M5iNFo68Q=DTt z?Sfzy!9n5Koz%LAjW7MPZa1X7L&|miiZOCR35aPaJRX;`aI(E}-6er%8Ybx3ZlW7v zyO2Dyr`LS!P#PZQO@BvZo>;yHE@TA@<$>ymbx-<{cdgJmwH|GAqYMrJI2< zqQ~)LaVh(D228!DzX1{n943W+0{pzmx)?e`U`TZff%!ZpM<58rx2LMom`jW)aZ6@c zuLqW;6=M#ECOGDXMP5T;Flt#S9=yRI{PyD+|5ivX_G|AGwT8Qf9YvhUGSt`ys)FUx zjbF6XJcSzNt_FV?jt>}%9q$yEe4tI%{%#U~HjaO|{lT_Y0FL>ty_ia@2? zXVNM4F(Va?V%O3RH*3#M$I zn_;oikD3q7%>(5x=kwhYawb1zRj+B3hkd*0-YR1dq&{@wQ2|iu5&3BB$)!{4D|TsA7tcjkdK-QcldQ=X-J3F1>54#LL^NQ<9Zm7eLTDdE8 zQ)?0o)&k26jM}~OW#u`2f3E{Qt(EVcY;v9T#^SuM*x2P9m_mk#RZOg(Zimg@*~xZu zV!NE~*GO@DnTe;%yXk!I$5ET&l^Yo|h!5^1_9Hu^%e{FHLos8I6|xgt;e?&4+08gc z^-wHsEc!GLe&-@HEwV6!foF-brN$;Lia|M7O*i?sE_sgS<%XAm(NAVOjw?VKY#eMr zc|!jrfY%wZdPvv2XIRLjs`w8r zM#1taWaq-`kW&IBjlNVPiXcmw_$%(0=?OYq&O=4kE80O(jBjH8q)u`>3mQ7FxCH)l z^ki9YE9SNwP4b`k2}tw;pD|1Y+(}gso|HH;Rh}ttg!NT zboe9h@$W%-Y)`}>89Xyh<=k^|_zYmuY7w^|zCh6W^+;b78uru0t%6RS&dQ>fz>9Xa zj1}VVe62YML8!K4B*^~ zH=sgS>hC*|RpPG1U#}2~9w@&kQWeJF54EcUf9BnZvy9d`_HfDJk57N;@}~xja}s-W z6KjLKB0Xr&G>B)e!BB%R8rc|_=ryjk1pcbTQyB@o$lLT+$V~o;NQ*@5pk${OdEfbB zWe{dr5Q~#>`TByBQ7Z|#YTBLcB3G^@e>3@699aHc9ld+?n=I>(J*)^QBs~Ih6Xp13 zQkp!#scRS;8R8H9WVDmjeXP)647k3HaUiGmesfQS^J>cwJ?T=}3A{`}*m}0qf>j>Z z=~SN^QHxFt$kLe4(mc%KZ#!YM*}Asb`lytd zo7qM^*(R#l+Vj~Y&K%1EPIJ{9>);%lCz*x?IS%tVj;b6N4|AM@GkIE3OXO2OrqM-I z-z)VTPV>2x0!|Y7)E`pb4bM{~FfVW~H)K990Rj(vaw<|aKN1D!0n(WxU@s}?H4--Q zNj^fB{v{3F0brZMk@2c5cCGaEd-*8|9QHeT74w|@#QYku{2zFzpapb;f^A9wuMrvJ zQP9G4(1`@&CD6YHm^Y~CN)o6CAPW+}&~ygWULmtAT|dD5f{frPFP_{f<{8YZv@N+I z%lHSM|EKlTQTnN)l~YlwjO@n+m@!-IrY+c(kS_%?KjOrMPBYLG=y&Hap}R#$|564g z$V)suI|;TR1LrC)`@K^JaN){5OOS=QrSy{DttF9%rw(QEm!^&M@Jugd&`D$n3<9mE zpSlhDt1 z0O_N0!Z_*$h55w_(;2RlwkmW#8I)>ed^24PUq$;<7=}niXj%FkTW}&By}H6QNfJJL zRH@a=xF$o_Okv(?#doBmvr$mkUTGx>Jwc>{N0hlTRKc7O6C^Nsw@87=6qC*{DML@2 zXS}dLA9qZEB&MV1X~?+M+HkM3NYH;+!B-(*T}=b~+iBK~?v*(cc*dJG>gZ-ve$kXgnTLNM)cg z6t#PT9aJRq3UpqE4(8u-qVbot4zhJbe=}wiVU)qi+N!j{K8rG)fRji z(memZT2h?;)q7w;9MVjwV4kLb6JDE4YEt29`sUR<*U+3rt!4%hFINBs3Uj+1Y`L|3 zWu+KTqTXs{#E~KWyA5c25NvGew1X}KR6Lnk0AB?c4?ShrAh*a7-BYrBTyUy({1lTG zW5;v_Op9(4tYDC37%~J^jX-&jnF-RNZ4b7Pka1dc8zf=X-b#IMX6+x6sR?+Z&qN#k%1Z-S3ZD>S-;-P zsD^$?LNf0@K(2NoAziR?_+4YLuoanO3{IwZq1w7`9(#jN9`rrs=9<{;hC`6eM8?VR z`#%yOTe~e=ssmHBKGFkZ$w@HmR(FCim`E-|5SU+*9=^mE9W*{%Wb6j)p@}O@qbv6q zR(q)GgSImOV?#;3-M!z_=vr@3p3J-;-pSXFL&z?Rl4EEAwT1hZB?cm@wRx0s>DTlJqPdw8NO#Y3d7W)-Y}3Rx;Pel=#2(L zlG)J!yf(OyMCrv&)8nTB10wSmHKwfNbbasE=3*3dlGbuEDI(2NVNFGIEzqBztlt7? z%+#^uH?@=Ekjj--9Pvr39cV{mVy9F-pds1ukcUR#L@Tm9xp$M=eA^hDH3nbcixu$9 z(jNi0iGFDbhAn&_95MiNg1-PKZvPr@)0pT;9ze?=TUzmzt&G>z&_XLfA?<0F!xI?c zX?t?-ybS%H0(5r*>@_1a(H^?eiolYfY4*qm_}UBjTK4p*4{s_~TIsRiWYBx)H7a*V zI(k@OP@2$i>-Y32Cwvi@f2R+{n+!=SL{GLN$}OPH0Q2kgayiMG4iI5pIPfMN&GQK; zrl23m(3g-AuFh@6#|5>gd7le7ASr4L%I|^j^yd=IPnTuT55%kLSJ0>J`jpQ+FIFqC z6Q?&7XMRDg9#^fNb(mzP4a4?cNH-Ss?GzzoQE$T0@m{kADJY+W8p34|Kh5|8&*Vg8 zdi%T7a)I$}@^kS}98btApZele88pulpg=|cF$OOXneLpWKSO{dlPa2bTf)$D)9jE1If(^9!a{FE30q0L;~GvwYr$X@U2KeDLeF%VvLdkZ zBueglK`u$A)Olw?J>umwZYJ1a@fKl$w$vlT2{EF=FyNp<#v3eQDQllkPHU+=^ki#j zj6-&D^!U$`TEtQqVOdFQSs_BM>eJFn|MDx(Wvv3Xcg@R+tIHl*Zy%wTDtVU<&@(@H zmxn*ie>|J>hj-=0r?)nkwTT^)dtozme)1^t`qq- zv^6($9XIsDHVjHPj0QGLmN(4)ZjkskEj2f-95=1QHf>5b?FKd-mNy;$Zj$-lIcvUi zaeU_%_Rgd9o!7uSpXGOcf8SB~wytSz1vqZq2-^xO-3l4ly1l#=_IE3sZ#z?Vj|5?J!YxO8@Rq|H`w2gmS5knJizmGM09}@&XI1ol!{&bG+vs%l0fW(;Ex+7@C z3xWWq6{}78bS_KEWE3$+Cn)j!9Y%&|hJkyf12T>(?w}~tA5gu9u#$mF`RyW~tw~c6 zJi@TODXjK1pSl!mAq;W(9`}cT0kNg+hP_&Ipnf>FC-dv`n!xdNtaCUW zJst$#@|}6OW^rM69J5D<`Fz$4E|}&<_ho%7?#|r->_OPN#Pml=3&^6>dkf0$vgW$_ zGpr9D;n@wD)#TMa4KVFG(XFhr?`pczIH9s%m)yU;UEh~z`+oWOyH?qH{lHG@^yfk; z;2aB7IBl=PPfX;b*U$;#ETei7u)6T<-SKBu5YKbz?pjxsEPJamh4qU->we~)GZ50@ znE^Ej3Bded;ry}&?n0ICt{H*{(4ixF&Hc>PpI^dG!^3ZLJX^DUhW-0hKx#RK`7W>_ zdsy;Nd7l2K;Oti^so$j!v24>{u;;#r4M6&yVbe~-Gs@Pafj?ql&^yP{U{u<=xilwp z>p_h_kb41;j)nwCulGoU;EO{q>fzHbtO7EBo|Ua(rWKh;zxF==0x-nE1OVP+BbuL{ z5(Ti&k_~Xw$ozP=Gmd?t08L-uZE5KB4*yCZ8D%chCc2@g%Vi--xw%O$D)yb-V6N+Viz^W*ZY6k8Jm!U<_F$v2HcL)jZ2R{}LaX5L%(aAgL5TrkuneO4r|%f1QE8Lp-s$3!uZb(&$)zpOH{5 z#G=Cg(GC%=0*%G-Vuj1b2J!D0#EH;B+KC>W#lJvJ5LB{Rg(;2Rqte)H0zB$5QwBs; zp}al=@uWiJAOSIcG|rF8Yr6L29#n%;lGw00SZHvtp- z6$#k^;R)r14dArs%Y4iGr1K}9u|&UQ(P>~I+p~^^Ri_RZ9pnB6XLr9SZLNhVkqJi& zc7~&2viU}>a=D4*mdy&4m2lC|_e=?~{Acb_&CiH;HeKZH5KTfem>{9XXU45*zJuG= z70kv*t$6hNGh)N;$pDp|MbC>(qAR&^+k_j=jE4#Pxei6jK|5BGiv-UYFnJaX+Zc)n z7!gzUy6a>cSt?rNErrgz?ZXwv$pTZ-UmhWoFGs*^|v|%v)(nMJJ_asb$-)=65OQZtt1)ZvOTeYh>U{3Fi_=G}K_l z5gIEp5Cql!U5y5em@I(xvU5AZ97%CNobZ5s#KCswKiZL^?f7s-s1msX^)dE7k!ejU zY#{XK+qiRKhe>(k2VfmebKo%P_M8v8XlQ5G_ z89e#1X5bDO{yq_Z+`Tdo1%S$Ep10tVGDZ;l#m!k1^1BXLiUG$5c;{ZT#n&6XZAFdgv2Ax zaZ)&oGd>JFCPm4_7(Cr_!oyxqy8U9Vd-{`&5_HOT1+|t3pDmw?gCQeuj^R3}*!|oe zOkB!}_2y8ScclVWA`r9i7?$^$z@dVpTl`~AsEui|*NO@x-nv8hx9)q*x5MVhPa1T3vgz=XpH-;1?6SPOuxS`qTFIx|TPEJ( z52fv9sL0Ueh{XF)@!OPJ%>ANhl#J?;>(ek8FJCAU6eAAEGCX_0E%H{i4-(uNbVkt; zG9~kB>(6Y-FiV5!;{C^K5!qEfXS{VD8fkQ7TGF9ZTz}(0{-MO-%Fm3IjKPOmP>p@6 zEp_u4*-Z(DPVd6IU~X5Gsj9UV<7r+70?<=Hy`(ZKWk-CGd001t?~ zz7`V0GpHPw7o$2V-F2^e6EW8sUCQ;Wn4l7675A8i(8n{hFP(mt_%l)x5ndYVOoZ4m z8ic7SLDP8&EMbu`D{c{xWFg>2r-Z(2I2G9Yy~5DF0w9oDxzLy8x?)}y@4ZenhPcq_ zE!Fm5ScwqnR>=U*A{~KInJS+kUsX1fiTZ|93I6kbzXk34W(Tr5(Zjoc6OA;USXwu{ ze<}l+R=KRqPDb6zxe8;zNB3j#z^aR6;yN;xg_WxK>bC%7R_Kv@G!6;Y@~!VDDO#Ufa_@9I%912h~gZe2owJ z=g6X*=@#1sZsqWE9ElN+VflP}RM_@(F%kLJCk6Zw8L^i8YGzm67u9C+T4~CBz$<@y z7aL9|TNlCLIr)}Te{sOr-7eOLO8I4FjgZwPR1aVI47|11I~>tNhm?!Lt_{Uxk3V_l zp(@HDQ@7asstR?h#g%;=4-1njXZo7sgbm{j$G(I2hNKLYLmKDw5gFZ;$uSw~>o zS6_blAH3aXP?L|oJ^Ck=8cag(N$5QkX`+PQF(672F*GR(0%8Fyp-NMV^xmZRCY{iG z6AOY!KrA#x#R8(a(ceDj?E7NhIsdtL?(0k@Gt7{gJZpVFYpIEkgnMfJF}-H@nA9g} zx!!B}PsbtpNFW*XxpShtxewUhLnn_j+yir$&t48VFD7Bd zBQ@=*Z*g8hi^@frc8`5=TG1s`93%(a8JxxYJvg1kuXXAC-E=;p8h+)=yroKJ!Bk+~ z(&X@fT2%Dtq;rBgIzjlC%=U>P+wg=Z#(z>1i4A#;QYN4y&w*uPXl)Y zD+{%6ZQ8CJoD|kss_VV=;rhzY6$aWNG+}%Up)P@3cqrd|x3^wA>2ntgPg}Ir+GD!IH zfWo>?VcVk|f%YNyWYk2oQ7V1x`h6TWeZQ6{oPmAZ5q&%S#;P%W!P2U z(775CKnisW9QI%xR%ayhkqt>4p)%@sHOq&6)`xxfhA%@$+y*1O+Q97ZLruz~F0hVV zbsM=BIC4E=Lo+8o9p%QrmX4|X6i(` z?f}w{MIp4aUusF24#^o(R$G49XS$t)@?Ea3&$fF^?4*q9(^5$2tsM3`v$?2NE22e zb-lm4vvO;{A-X6Qd|G2R735}; zc%R$KXjzwoPZUZYm8C#+=({g45W}9)se3RV4D}k?3afujgv=94zf&g?82L^_KsXQV zcd2?-ZEz6RiOPK>{FG)2G!H5px@mwCvU#T~L877hLaf~O_~8#?tv2+Em?QMq9nG6T zJYS>$YW)ySQsmx-NuXD0Hkug9!yXBQ={560b%0#UJ#Y~sm$*s@4k%ftpN{vZnk0Mu#A7ou?3h4Q@6qKlAu#6__ z#ds}FCc<7$FA&i%+;IoMpmuw;dteQzd-uR+_B`-VDKwmHVRNuau)ZUS4#28FPSUkJjXaGK1-Sr-X~u#U(f30NsL|=mDuWSioET;?K7J6f zynpf%i(|5@E(h%l$8oM0XG1Qc13OwIk2mS0XQh1~Dw0bFtK|V@7A4f(eo#4kbp0+2 zRIDTUohS3STO@q!x&Es!jgeaZ7z;+w<3k*Z0grWOwG!0%td_{h`U$WiAi1osf!|J+ z15WJG93FdNKORuZg5nV((XkJ(oXjf9U!gAJQx9C(g{g4YDsJ$`hWN4 z1l4lUX8d=qQ$T4!awhsW87<`zWy?Ae`RC@~QC#>THKdT#0 zhLW&~Cae}i;?hF;M`Kd-mmj=>D}lYwl|AT(zRxO>o<0hrvKrhxbpXzs5BShb{BC9p zcpl7!Pi|E?BTgP*ip<&=$u8IW*`c>1kBNT$3^hw6aA?8dNFOqj1(Im|e0@FvPmEhv z%+i(ivKiHZ-a~J2K_f6Wa;DFULGQP9GS28~)d1DMuxSLXge%!cj-sfp$LRvk=1+f#32 zP2*CH*-o>GC}>;ATS!aOHMm4#DRzTla7qLG7C&%+A0 z*2FXC&gXLX)I7Lsn^cz1N(7zsmW{q4mHY~*=Ehc)dx!KuOF)_$r;sQAt*w0J;*jxa7;3$l7|u*Wt795~4n1LRl3)T%QE{pl>{jFQ{d^ z&n{0&W#gAS=3vuz3WJR%6*fDNIW|k{#o@&20}ZU4@)?Y`D?j=6MHhu{thCWnoQx~t z2mFb?EILI24)>D+*F}ZhQlUU#e7%g@12%i?(&Hl?`qc*YVVpWB&oCL=&7saWZL9>< z#NyYnp|beZEN!1UHdp=mQG<&x8#}At;;|}-Bx#&;u&tZFxslbwTN#@KM@0nz@ ze<^#FPKVKZ6`#eRJa~)Y0I!Dh49mh>D=CA$A~S9N^=_T0q`M-Ck>H&z05&?!f}WQI z6P+PXY_6V{)D)hxTM}U{c}qwvC2wjfW37<=*9@sydAWq-XN`{{e_RX&_q}V<4wwpY zSgMLT9KK?vr=;UV%z*xIKRdI`agnJ=m7XWD3b_3}dIxVPu&~m|sA2zK81NYkXqTy} z&WXysc;nDXons;VRVx2zb+k4c3Gj&2C_bi;v9_K(-N&sv_4ijB>4`(W(AOr;B@FA! zXWgg(CDADPek5v&S*b?hOLdvQPb}jYUv|g0+s9slgLF7}PJbNr`2u@rWeMG94+SS) z!Y~oTZ<9o?cR(u7!ESIzGsa(B-IImF$|>Q@C&@2;?VM5Mjk`>Zq4zc2c33~DQR*UP zD=&IF9gJzsQ7n@>-dZ(hzI!&}@I2yPuO;iwV_e=^`4B)hWvmTKM;36`!Ls~|A^X;! zmqL&kdI`QPuDZO_MDbASBdpp%!tbs!B*@@x7Q!Q%2C03Dgbl%Tme3Gx8$;N5^);P) z>3Q6g}DVM9e{r9|uivq4>#G zFIu?G!XRx77#MJ@@SzG=_xM$In4_QXiFq|$QMeTlehVVt`#HSN-+Yh$R2(BVWkYJZ zD}sPV*ko8a!MM34ZDA7?A)#k=j9fVTkPWMeK#Zu&oR<3 z+9}sKSMQP+koN*ns~$WIh3DVg^<#e*#7%P!6H67iu`a(E#V6*J8(dt$R5WfrM5`#`0e<*BL zS?o=N*Gyk{u83p3XLxZ#JO%|)OpRgei|etIoRW0RA4Na$6nI{af)HcNJ=syaW{>Ue zvnztbJ@0R}-QQlg|KZ2|U7m!`>Ir*x3Eyrc{K!Z+XiGR;NcjCD0pLvpYa~ML6X8LL zjG2kd?TM@}64~|>k-SN0jU*2HB(9(&9ur$^Ym&f=B%%Ez3~w?{BU#iwS^S@dM0>LA zi)4unfZmY6ZzQYyt09s3K(qZ{4G98oiY~n&A@#seN=QHRZ$simisk;_hJ;3{&5I)YvP)2lSMr?bA0aJR!i)3Kk&&`;uE1BsP`)U3gnGb@}8^^M4nPi{e&#JdiOR&#A z+n&`DlX>n%)*2|Q!6aiaC_AMhyYxlQ^nT8)R7$m1W~WI`FK2pqY$I#PE7z?(Z*@N}I5XGTK5sWDZ$~5V(^&2zZ|>oX{NMZe4jQ>z zdbv?AGH*#qzA2tw3#Qt=fXlMa@u^zQV*#71>H=%ijNq*%c1xkLB{sqN=9^_9wAgIX z7Z1<#RX97?$^h^Z6hOWL-*qmH?{o9;gR>)Z?fl^0^)a9mhY{p z#Z={isX~iD^Ru9mLE!ujj3-~=K#(BTuOz@b|9MO~k7i+-M!t|{$@KV9b!488OGVh- zYGQ0PxiSZBTGd)vf*-5$0N_UB(1_R?`^xg?yhX04h63;zrj>umk9NsEZ#w zL9c;6CMgsH@g|3u?AC?!si;&mc>BR!{2I!xfZ5I_TTmNAR*kT|Z;`cg_wQn%y=Vq_3r(YV??`I&$Fd1U`7E=Rysl>Xn+(KH& zTEEg|w$uk*GwxmFB_ni0Er*?0^O3p523adZt~pgz>>8w@pI!IhyE^!M=q=U>AVb=rMo*xRl`W0VCW`FDBnG66B%4uZn?ONR|9V zxSn^?NyMa=9X@+OMF1$9MRmHw!DVpV;2d8K20gChlo&vM@l6T0MA$!rbhgcj#A97_cE zTQPMW<%iw4I~36G##7&=ezsYdX?WsTR|ntmv+RQ^ok=`^I+i-*KiB0~cvNo!=GCQc zK@MpQ7W52guw`A?)?jKRt3EbwCa(YtmMe;5Q#5f-TDzuC^ye6v|*sltAoF5goLS*NrY7%$oK@vfn=-sgnt%>d~Zr#KYiq<%rne67|bOcL_HB0i*?T5YO zx|#X`S!u=UxWS8#9U)jy;emWwh^7^_-k!@yy&k+JJ6aYC5qvEEaQrALd)&NY$lr>1 z`Roi@d3Ysm=JfOi<2TNJxw)iDI1MT)7R?ho&a|ixP3hF*VGwg)w(D18Esx&K};MSewQLd`&HRp9??O_KhLq4@$m2E-iq>0~a`1TmsSxZvb z4Gmd6D!McA43UfrfnTESVn>#S<8`X?H+y&{!Y?3Ry8291A8(Khd2$J8;wL@po06Li z(Y$z*!m|BJVqSh(7Q@ulb5cu)rZb#h^IVr)ul6_z9y0t?PQvtO&&B1WBk~d-WfjeK zEAkhI*JZkpC;I%bpte%9lI8)-srz z9m9DKnTuIuqwL5%Y%*dB4&5j=?n{J9@7ZDQ-}P(V+~U5k<{(n&Q$085s85pC3#ZmC zg=SkUW_fyHIPwu(@CZKUK?d9Ulqz`dTAC%0Kvsvi9_#+zevta5_-1h7hS!mfoS0(G9 z=7VE59`rrpcRyt2M)<)gmZ>w#P?@UL!VoaGaOdbGx9k+pZ;>tR3=eu2+%U~O$inSi z4=Rl75~EpGmTdM|M?m265=p7DEv-(CEnQ4ukq28Sh zep-bzqRRJUkHb84V~WSKc28qP(O>qi`MvI^JGc!d;D95@NlE!9Pq0=iSH+XuRw>tO}h02 zzq$8&9Hw4SDJ0uKTioqok;Y=+We4Evf?pH;v5LP^#O2mrEdifLjV>@E1&0b$!t zD2>JkZXJg$+^#at`1NiC?k-H}SOm%*&MVC%$+&h-ecW*MIY7tt#Nry*Z|%Tqf7UI~ z8xj~(b|#*BDq|uZ%FTr4Q(+_+7!R-`)l!(|NRb&)3KVljN{LB7Cq~gPC<#w7N(K4F zoBsgEjf-8fZXM*sL}Vag{v=N_gk_Y8k-c#;Q-#8u!K7G^DsFy=l;#I>_{0>(+f*Qu z$rX%ATe=M((egh_eJ5)*y2EZQs8Zr2)%D0;jLo6?vF=T7Hd3Od5GM2TK`2DUWH|!8 zKn~>bFN%o0Fw~Xk=dTxzu!3k^4ZdKYLs2gW5THFzhtvdZS5)#{t^hDj%8Ds>*cs+fFMO(7G#hj$r>#hR0*b`a-Ftykk+$LLSjLa{`e@mE?CH zT9Q>ru4eR8G~tz}WUh?l3zt1>Y&k1$qAUB+_lq$C@0(1OIa*(@Ko*-$B-DbB*lb7@ zm-Or0Qywpm?GW|tPf*${anNN&C{*ENl_(3_P2y)9aSHea0CFO-t-9XoHpW3ZE111>?1|zMZ!kg-xp-d&w6}pIwNIW_okK33T>G_Y_i-{m56Cu zCLo^H{;GfJ(S)#;yRm#au8KP=d8@6}uO6|~R`U2!jq1?pa7W*kqU(?3YI4<_5BV&4 zTrNXi`Lqs~-_UWnyKEifQi1&Ttq@kqNeaDp^3^xDRP8gx^gH!=F4lXQ7pd`AzYg@x zcr>y5yiL9H?c1xL!LkE}wNI8ZJo%e2%^RYFSN6S9RTKAVi|meY$b06@ryUpT*w1v- zRM}qgf=u>YkiS$rJe~E55obpNwTZN$eGa3Wj$Q8l{ouL)Cpj& zSu%q@3C!6>VDKZcFW28a-qFCsik}VR9wfn!s%uH^7Sn`UGd*vk?;d&hH9l zkKAsajg*f7Gw>yLdf5yJ7*Nk4E{|%6+PvmlYZJr-D-LX@k~s3`v1}|nWDeE2m}=Lx z55!$v>DE~x9QEAMl#C%c-&*MUja(f4dXcX>^qTxETy47Wp0^(xG^<?v# zt~jnyZ=IF0purt6kkIfzL{OWl!^RT~!5|H>(dEW^&mO1k6u;T-m>a#lT^vapz01<+ zJT@DO;e1+dC~aD=!Gx!8PJ0gVh!Ns0`Gs>~Xzz2x1?!`{>aEyHF1}SRZr6}g*W>Rm z&{5SM8=E#Epk}s3lyjM;6vv(U*2|-m5AXx%C%XcJfn=CUA>ssjjx)rV{>K7^ow{wA zlKXm4Wm*y8Avu@3D~c28a)uj5zZS@L)j!&%$SOA8fIO-auDP^79i~|TeM2dQR2STv z3UWnEQVq2PF$@=M!g;T>xf2u8&5ngxmlujuLPTecjeaX-$Ze0j$AgR*%nQTVNc!|k z6p)433}Tys8C>pZ2_mRdfava zMgU%V`TemTYB+ zoND^HS;Vs|k+Aod)ofq!mf{*yC7}eJ??h{t*6xp22{$z!F}kP&kl{BkS^JX~HGFIN zE;RdbFSDHAA2007ImUqIqu#62#Bhc)N~&>Lt*y5%41H<3%MxO5aC_l3w&<*$Onu)H zIWK%D2cj?I*%$vIz%pA!5+>(K)49LvI}JYZ!4U$tiv1SVH@a0)4H-c-bT&YE?jGv zzFxcIb7c$gOW|R6xmtnCagG5bU+y-mJ)v+{$+_QUtX_l)j> zZcQTvkgw|S(xc}-N(jS1(L$xO|6j48wnBdbjo7j=`0|z|!oCdv6`EX45bN z+pG71J#*Zf9I6H3Dz~v5Hor7z8aFwilkc~1!B$|Vh|t1tzesDNhPY|e>+EN(6t*}d z8)GL$;Klo#e%=p$6H$=6S2ExPIUyp>g)HFORSRKmV7X+8EyZ2_aZ%&vB9-sjl^o+p zDBJWxk7@Rm0QC{nvAa9uv;k^%cF@%Mt)1zqy^dR$yJB7hHtKjNf9SdP7I(`pmBUXs zYh^?6-++(Djmhve<1&_YlF4zm;=+UB&d)#YQM#*q*@dA$#Nn2^UVg58;nD3du0F)& z5|?<)`yrJGx^KPPQHgu{#j>h_)qE1f?weznl-u=VxRVs+Oh4d{`1D$e)N_SQHB^0u zAGqMH$6q7q4;X*Ef#X^Nl?{|rSr0YtxliH~8jj$b)jR^dLtJ-WJd09$wlG{Amr~i% zdn@MXIKr8*$2X9nCozcuiQ@Ix7yRJWXJ-%wc+}6f6#=;ED#8a77EPr@7>jI$+1z-| z*IC}&#ZCdG2${Kv@-0E{V)8nbvG74bv#z-RTnd9?re4!vY z`Zi+#F=7}akItqJG|IG(i{6kB#V|zl@s{-Q{i`9-C%E1x^iM;AqaQ2!uZD!EO~2Sb z4T*?;$&`LH^S>?d{l_5uKfdtqx%&SH!9EG3Ne|p_{);3KFy0mTPb2|-tY{&gs0!XNCMu+B2(Gwe*<@qv9uF^0(XwmsUqVC(&xsTC1?MT1c>0k%BS?e z-Q`wgOV#r_j;gRffxG>E$C=7={HJA?9{Ih#W+6jgP|NiFLlUHmFZYlk9+NVE7Sz~j zIHyT7(5#YmQxuf@v#pD(DL@p_YL zccJ1!?Wa4Sq6%t?mJz7Jv8}20)!mcuLjhd;gXKyw zSSThU9=q)jg-q0(-QzuJgfN_wm6v@zf?d%H<2RsWkc&ubZE|&W8l@VS?ZIG zcVpR8SmDj;LUJw*YtuB@wdW$Hl*kor%fwH^f@V7^Pm(qTaVsDs8;+`?8_^o0Q6{?^ zqj84?&dnAs`=%d}Py9S1XG%6ed)y_ez}>t2zA=~ANkX{c)7wTZuCpQ*;{05+7RI6vYsj&6bnHcaR~^$d=+UdI59)T>h^M#a5& zAHv2+7*VBv|AjK%5n%@Lq^0A)$wdA72f5$&T23$&)Pe3n^5B9Log*FftSa6BAmpMj ziN)*xJ~+!o8yu2n@auDTjJA0UCWj(N$8B{b&v2^DY zp5t~YrPVn!!45Jo$%hFAICgHB7l65Vn3Upf)iYrS&Z1+ZBa^xbj21{e;d2YnM1R)k z{w6oxOQSe>Dk2KgC>HIAG%vuh^u)GnaFUW`hw^L$b_%kP9(<lfO^#XkXM7MLEHw$MlXxS%f55+++94b(T{*s>@z zScZKA>$5#^^`&SX@dIza_TaK;X%jO}tNE-6(In(}#>CmTl?9&qp3xk9#c;y9K6(_V zX23CsG%0Z9nZ;EqaTg)=3z?P!QhUUyG6HUeK2a%Ie8Zy#QF1onGSLfh;-!SE8PS>t& z#+Q$So3jWoWBXGvO(o82$QMA^Rr6Xmfiq6*Ohsa%peSsc0KD%F`9cq4t)v@n>eX}H zK9;>g9E^<@-L(K^G1iNC3-y&};Rb3RleKS_*834{naWZ6_8DtZ67TRmH0D-M-L?$| zVM*Mx($q`(UthPW7DO%k?}kUcw5=DQo_(%aSHM4MTdN|2o9!8GMm&AXg*}FQ|CreE zeZcvRP%DwXpI$t{)_ zXnAsRxwCopKgPwi78|ggR#)eOFhsrZ&Li~kaD?@NgU(IzDOcE5RpZayAjqqGE9|h{_(bFdcKJtb6Yj7){)WlK{A1cUD=-r(xt#H^wX*2 zH@g~z@Cnp155zm8IQC$xKQJM>(f+JbTwt#Kr}0q-(xGgI#r7pEUMEXDnQ#l5e=hrgc-Wg=+iRer z8Y6e8Z)o5P;yw)E9@gqQ8penh7Lo}aTd*Bf{dA;i15l(?RtQWk^KN!dDC2XC8oqe~ zDV${CJnAM6{W@B_qpPm${hiOh3%1D>!|+SwM>{9xXz*Nlr2m;PMzw3MbzW;=Wry<4 zm)<3oa%+1gGmA`nKjklP;}NEm3kvsbI8?uDV;($C@rR_>|7K|VxSX^_>!&PQi9U}? zeKp=YsaD)~yO%d@^s$HoxKQd=ucSFDLkxkEY`+bEJf8RA_j=e&$;R#zr%Zj$nWuRk zk3O}bSRoINmHvb}&LDTbbdEk%rs@UWBz0y7AF(K>?eXVdL;cG8=EMGbddxHUU6M@{ zwXXEXMg6+dU+eX=h4!6`&y3&l2Mt?8;2y;a>h&tMuK~N=s~HBeJz)8ze)9gCQ{aa{ytCGl}+-Q%2&yXuJCz#Wx#Cyf%`D zXb&dC%yz+W*L%7cm1=ezf&x8~rVibZI}&;FLW|OqHm9@iOsb(ornfTBz>55>9%99@ zn>Ml}G9>n@vLVcN)79kh6BRJ%Xd=z!f$98llhWWtxBCc*1SjR&GM{4@C0y`V=xn~7 zkx2q`lm@g<^%d7W8TONFXjsfCrPV-f8vxFvuE(Gcb1z7C<&wYcntIM7$!3>i?|EMG zT@1=LbtNTD!R`XY%Kapl^@=A>`&!EO`};A)57h0Wt_3~l2ZzX`rC3AbbRVav=%*0S z7bQRAAs!+r8X~HvMfTqlRo5~k`ZIFdweDAV9Yo=>?Qxlz8S{g;0_|{VZ}39~B2V6k z@FZT@)t62#4HMNpSIg;V7GTw(fopnUg&^Jm`Q14kreG8RwmIeUT}fB75i~0$GNmkH z2M|Bp&2~PMC4rN3CtVb^&ef##!xos%1{!%j0pAN+*U00&CaWQu_be}eEtk5H2iljr z$so2DB>yo+gf2g1g9}guhm&hji$Mh%XmDFpfdV*-^`M{=iUXJnIUEYPf(v=F3i&z; z1r`g14hk`RML5kOQHLV&;37$Sv8ROA%Ck~1U zYgpY%)c+U{`0IL$C6=Zfe}D)4LmTfS#N86RtcMyP*s1X&P6rR2m|+41SF!)-4u0qh zv8B*|bO+2I-NCJrnW=LpxlhNuw|YOiU=a z!7eJm4?!icE#jFWR#5V6InNwJMIth06RAAQLd7F4P*4wpD=QYuY7bCNvqzj3kNhk+ zvR`oI_wK_cqKT+trNn9#q@g^I8TE&DkVgMQJB%NoZWUB8f~x;-w1ZB~v)G!&gGy>F zY8g{?NT_l;II_R{aG6rYWCiUfBIfJqC*Md+BJ)ckB7+1%;2{GAh($b;n{-Y5Zs`EN zg4L?-dsdxL3&ZmQLjWF@wQL)&IZ_5NyryxCSsCcEBU!3o8B_cF102 zky&C85(E9?ItaP9*s;|7<2rcD{B<36TUN6kL9n28huWWhwHumMe^3YHAJhTzU#NqS z`+uPh$dHH(D>~{B68r~saNA_P zp$XBE`GYz{@w3%WAjdkYr!@l-dFoRb*7&^%yu345ynI4E$52dqBjEY!f2EWCF`F_>} zXFnpDRz1o(a%aHNIy&c&D~&|SApdX<*gg)eKb(V*0c4$0g*w*2bBT>3 zp6SMB-#zb6rld{>qy8?wejym!&=xDS8aYB|5=@a|1^q%p{i+ik%EYd|#p;6CzIO%9 z%OUMjUHvyIndbO`QscZ@z<}n^*(>cgw-A@8r$DmIG~;I2#LkN9>|# zPE1qAa9xbKiM?;LhtA3(V}TmzAIo9#DW!b0da_CY$RKr#6);YdSdlkTQs@z;$G~gN zsyiVRy5(?V@{i?EZ`RL6%%EEisVdBFaeYLAzm~&n$2|eSV7Kq{O{D7N%o?fxr}?Aw zm)-1+Ww2YwqWDgyn>}K(e=LU=FUKMNHH@H%!0axzUwu&j2`Jri*wxm)** zJ(cKtqTu|LIrJ%S-xE6W5Xx6hoSkOCf^Gp|1R1(c>>9u`xwgO?;>s`-)_xfz4}pzV zT}NjgzAQ3uTReIPOo8g3`J8Jhk^vRtd#>Jk4k?69l0fDiEb$}|n%E9*V2#5symkS- z0Xj|jaV4_I`Pm9O^FR{-)F;QGvUKKQ3<7!#BEjY{FDzMKBwM^ly*KfPd7$Fy%!Apn zzsv)5DbVM6lnk=@_zSQzh%P-m&q6$ig_f~`<*fcCJvciub`~_Bq7^hx?z}VrmMNVK zX#65^3mia|p;HedrcNePNKxzSyB0_@gulDa(^Ka%(4c@X$5F(ZCp3!{F-7V@_tPIf zD@;8|kkbl-KNV$#d#v^p)kEd1T{-M#I(P6i8}p1I6y%Zp2Z(U6{R>23>cBNkbRa?^ zdx8!`hzk7=5Yg4qbAzu%B5&=>CJ;$(E~b>Q0gQ?#UK<}}rV|lKRSk3^;)lbScI_Gl z$8cG?DS+6xhDRu!t(3XAq|S;HkV6_WD2N51l_>uv1Am>6z2*)FcjFQL zNcbQT{CtU7dWq#W+iRr{R$ryxU7^`l(wPX+SAUp@DcL_vMBE7mUQtjywXOyakzZzs zt6is(nJ#;8)bPJ~UeB^>j*`Qz9Lg!MIbG+4uAcX&I{dP7zqSSO-D>b%MTBl0E^qEm zZP|BI8+}nowrx5)4*0GPz1r%zy~5$U#ra9S_x?&MN0orDEff3pkyqPb#p+kJ)MYmG z=>6^GSJZjS?an+ZMd$<5>W9~?JJ3}`ecWn)?bfH`+hfxoe((5>pIAY&aW*?`O*`$p zb=v*@VH+y6^UGrQXU~ew@<(a#mih7~`s51DhsyQw!;z1hEz_TBd$!-?QSnfik#v;_ zGi*Ed!`kf+4BFcQmv^mc-2uS)FK4Fkj{dIh``t}EAr%yD?9p1VRpFezR zv;1VF{o&mCZ->)c{=Iu0wI7*Ke`yTh3)AKAF4}uw%WtO=R(=b9^_}a3cdk#Jd9q69lBcA)p z(YvQ{m>m1~tEw=#{Xg!|5w^Wv3h6r(z>aQ!khlovw1a)xjlaTc`X~+-H$X z!s)(iUuC!VXZP8LK$i37n=0~-t!K`TyLY9!Sq(ZszR>$hUtT_Rd@i2n8CXy1B6OaK z-&B=*Km0)N%T0dN&bz0jw3+GQ15Jgc-r_qr1dHQ0pS7X0N4_JJWnJbIH&jo)==8N; zPCNcis4__G&B{_kKKxj>cwlGy$gy;-m$i=IfG;OcJOw zs}ZKEPP`^sZ?bWMS3 zJ`SnT7f9bcI)8@-QzwNoh_{i#j~J>uM{-|ibG|DarS1|VQQGDbr!cJUdQa_bn`?qL zT*EENNW9(c!AV06_f*>p?e6L4qckpLdX%b)uyKiC$`grBx6e8>1ivY3^{y0nP( zsO9L5NJQmv=WX%LsiGa^x1G-T-j<=lc;(tN*Ta>kfp8~=HlPqlG`dmfz)Au1?%jq6 zYn>h9Eo&uo%v5lUbLB2jfesD@>+ATvkU-nfS z#RantzghE{2$HxS(KbX`1-z=xziQt6UV{`}y)nj8@WEO_LAp8t7*uxZ(gltmP4sc# z8O`lDLvHgvO`u(Q*+}3>d9D$NNOZV_q=OmtpfQUH5K9Udq>;`Hj81^fk$SutNWg2O zj`i@1Fvwh8j-xU$@(DA*I`Z^rnMVIr3wBEDqK6#Tjd)gq1a6VVz-3huScF;acdKEc zO8TJ@EBzqO8=jy&tI!ZAPv0RWb@*t}kq})B0ThvF@KGc2Eb@j9vNIJbgC;RWYNa34 z9v$+bi$*+>6lfDzwdF;E zc$I;n^8Ja_70u9}rI7~Le0Ck!0M}MFfPRZkNlG-g6=R}A9j(;4|JdPSiy>yhZ#nra ziY6%x!AW&mT>Bh6?sh>k*QCZXD=x-9#0#kkCB?l5*`O|HzpDf=jQX~UBGOIFCt8o0vzN{Z%`xrX5eTNOx-w) zd51ex6tBX>m71o+MDHdie?DucUTjz+_Vf}b(b1vh3}DAw%NY$ydhQUWbzN%CKlN+% z^Kr43&rThD9af7QZKkQ8BI-9&APJ&UaM4Zrdv8RbfaH) zMCD$vI_2f@NYAJ4X9xi@C25dh%^GmZYUWCS%p<>9t9H%6rl&699-q97z|m)}TKtUM z%ImW%bgu$fPYby|JUujPLb^t(7f~o{2^AN0hRCRc_&q&9V>RRkF5kxtyGwJZK-n(e?t zr;Dkl96=;q=a$o}zhZ3>>xguS%T0$%L#Ynqxm6Hy)&wQAipSjzuh#TEnvoPD5FU)&X?J;E^B$D+4YP?q$ZtO_&a(2GRMXe5~>h81+ zPILetQN8(5BWxwK?Zy4l{xfFG8&>_-{I67{`P8_-}r^QZ$eAP~$c;+G*+FDM~^Nu8Ko)&)o zM)}Ur9f{zNzUdNNn?6s(Rj@1{&W1`Ip}>Ed?1x=4I!;YrYLhdiZB5^MLv3!BI3@oc zouf4ga8|#6>*bT@STyr&gmB4O!Hc(S z5p~QfCVxl+Vx3jMO+9+atJ!O=E}!|4;sGHCm&>Nr%8rz0{MiB$sC-+T?L7b-_0(WA zE_j~B<##N+)j6CsmdrUyxR`VTtWJSNbXiw&{dU!Yc5z*s=fW0Hlnbh5N#G_(#djC* zVP_wxB#p^Yz`7rhOwsMySL0yq^9I#;*@L8ag(LL@{I-N>cfU|Td#YZ_n7E(Ei*ah{ zXOH`Y%ax;>W*_%}%LzVn{e*Q11<{;p8TIF2i4$D|*!dnm=d7onvV;ctKh1Yztb1OJ zfrGM2A(Ft0pwOBa5pY2mqM%KsOVK|oud7f$Dy9R1(FY?Td+o|%9ckPJVUHTfOEF+< zK`!cjj%-1vqV{a8ck4t+zcj? zxd8+3mqXZft}%$NYQ4clsbQkE%-b(qpT^W^UP_8~q7Us^x#RY@gtOBu5B0sAjTWts zUwFwshgDmT0giVJoP6Dckv8$-Ep^c>CAvJ+j3+BIhJwq1y`WIZ#9R~+h;$S`5eG=m z%ErC~R>9l}FS#yhf|OW5$X!WGoN@S*0d`%}ht*wIoN*@5-rc6O5?PVk$ra)Yc z97X(Lud8}d!m{ch><@k;G&ogPJSL{2w1jIfnQ~`Bf~ zk`Q@9(_?7(d`g;Ktk6$XlcZ!Z%~lg6Pn2S{G1mM-DAyhS-IUf+jS+aCH}b>?tow+v z&9$LlWOOtC(o&lED5kf$p7ZrIM=^$_QS?y?*UKkU43G0dV#$)!u>Xs-_Y7*X>)&=0 z5|RKRgx(=^kRl*LsD>uJ2nYy*G^Il*($PTZO`0?j>0JmYiYOX7(nPw58Udvvy@}?{ zeLwr1|K1;-J$ujIU&E{nb4_NBb***&&cmXYDwRpE}P_%%>a0%l_ zZ|S794mG`r7oHi6Z9uW|Do_Fe%KM{MuUP}jCMzu;am{<40Z};)V zjj6_Ej4nL+H52tTY&p5HpIEz>((fohP$Nbme%zyoZ7bOA% z1Tat{FfhQsofA$NfWRr3nwIjZ)PG&Y4Tb>N0eqBI3jh#|C#;mxQ~`xtuu390cg4eb zRpK}><$dvNmzYLsvxEjx_$a}d!c3q+90MN<`UZiBrvn<71Q#NzN3vuNt0DnRE1;;~ zZ+3;(m{#9=@47|i*=)6$Cp!m)rp)KrVIKBgHil3moSKS@)ZKEwff zo7N^0zPLAR+2a-7txp~cReb}7GAx_88-1&41TnFfif8_8qjNmGeVb@oX5__=(wksk z>s}m6zx6_d#QMZx9C-7ELzMF~hLT!3IBKWxU;~(YZNN&O>*e;)D{2V%|J9Qq|MMgY zNIe;n9^36%txMXmF-UxP;t<*T*J zG31P}q)bQI-CfnJ9nhYuBFS+dZ5y}2-@WB^3M0-X z*lfJ*90pWrr`WJv;*)Kwd5{V@ft@e?yAe@tdjIZ_M`R&ikxT28Srz&i7H* zD^DENdk=p;TjAqC{?8+%ynF!?z~3m!HZtHMj7R_fvH#`&*LIVq|AeiE{?l#}w*Mdh zOYD_gwf8xRBg`UK{$6k#X>VB?$oyb|(rynd(T@Y^d>wi9Y~@3#cD|KGcxry{m3wf} zMxEyyvjo@SlJwBwA7bo$t6%?+Vz>0$J?Z#O-%!FM zu|O@HpYE@YJWD0>o4tK=Iu`dN?3Vwdk<;UyrQs*H*rK)%KU~Dte0cYcOa@Tta`~Nv zE7^JjMQcg1aK-kIG1L)y^K1xfkMHpuGJ_6r-x%}0CsM*zE_e9?SBvk3r~MnY;`o#x zx(#vkmznWcN=LU+JEx8RV7!@ufk-T8TG9_z_(3PCIJ1lu*M#pL?IyXnnEe~JD$nJ6 z&~W=dVXKd~zv#jogA7yZeir%E>v9F%kx6uV6g=bUp7G*`W?3jZoDCNl3c0XaN_m$N za$x|M+T9LfT3@ZmJUi|Q%=^)DQ`p{|bFI2K#L&?x{3o!_vn0=Jy{@*pe!af&#rk>! zp`UzVqw)Dn#6tFqpY>m?~ca=U#w&wKmTYIVbQ$L5QT?bkc~lE2;@%y|FmJo(x1>+Si`#;4qz9?(`t_q;`8*YFIYf745`{8<)}A40f}1?8M8amBHQhd${Iz63`=Mh|s|vzO$V~47?mkPSo!e zG#+8EX?+34{>}6%9 zRSJt4yf?Jl%PttH6jgfv-ZWw_rxac#u4gc0QM8v^Yg~1~=KYX$$KFFiT9uT$!LZ%@ zUS9i1l}zaSVaKz*d?LJBHql_jg=@cH(70MY|NY1vmHoo;v}%PKgHbQL{i3;%YQ>lD zNBtu9ACcfS=mCSVz@q))RpT0!+4o~19s7@W(rVOJ3_e86@0Xm6)My;PCx5tiw*Le` zUyFenj>mExl)_AEwb+No6I2e$km<-E~Mr*Gs4SmdrIH*9;*XipSPGlDy zREnF_8QKg@}H2%UUVEj#ilph zTrr&Om_KX^8*Okr9-4i7cG!%gZ*+nh&2@7f5t2+AUD$```c;lvGSeH~#Ed=-*&VeO zj5gj;qB!g#j-Hj$KlRWvnx7~-dR}Yt)XQdgex~E7jgbD-$KB}jJbC`;Mf>PeztG{& zU(b$S66u?;iAD>HT*vK$CQX6)!wWxEj$e(ZHwD)ieOb3V?wA{G3VAvFWjo^dHHp4C zY{2O2UeWQJRg>n3+2OB89mkzJ>CI6qM&HinkKdk*Hs3oQ{`U9m_#FU2z(I{kRNN;- zm?1BO*_FP>7Z!J>x~DM<>1FrY$KpBa3XW zPx@ptTGHH&m$*Kk^rOdGGD1g|_+yr|-=(T61fR ze_XIX9kLy3&3ifWLniWc*a`8hV8HmN{G-zm57TEwvm-whU!UF|#b!J!UNK(zXX+ws z>{-e2$co1A(+@br^HQkEsuuUzc#{pU-C6$J&}gM>iaQpUn~xF9?Yy zn=ahH=LY{$_ILlo`?2ERWHd|Jc+LOF z+WwC!vK*71lz*$ps&7r!I}E@0->}aA@#*zHuzvl#=^Ler>_5AYo(rc;qu44rcweTF zQC?DeD@E3J$@}ZbDfSx7Y#l7mBA&qvacwTPPlri>BqH=HH055s*h+aEwDEQH^~+!1 zhzw36D1(LdrG_p6tuI!WH!4Ek2;BO!-m|qa#|rs2*7^GQ7b#qnd_q{FEmHNX+&sy2 z+Sg^7t{(o@7ge_(^fc8p`~G=R;wAvX@f8PV^B~0#Z{rg9;EHoj08WpPESWz7ixAEb z^DrL1QQmz1tM({8I>D-fARbX*br^5#f0EIyZ9TjZQv&e_a(F48C4>|(fGE7t+ZC{I zu9qn=pqzsQ9ZK{HYaK`1B0)%u&Tv2ooMqALYwhX}H@W{Lqa`NU;f7sAfX@qM0LVu6 zg!&GfdO-07h#Y2EET+_XoV{5;bnNnz6D*SJIgB<#(uRfQwx&)};HcN~frVZUY)w90 zX@RA3G~oI@iFL<2|H8VzT^n$>l=QQ~r<{yTurpBdFMMMs!Yjw2u0)K6J^Z?$#Y##A&Ax>I5wFk0VXr2fI9XN07GIPp!Sp5tW^ zH^?AxK|Y$Jdo;iv?j{9vLwf4-4~L;YMwjb*6K>3j{sZfQhs0QmV99`Dk2$Z8LX!a% zDSVo%hB%ge3sfdzI}p!Bz1%2jN=^0Y6;}z>mgGo)1xyEszR5<)gx%^DFc?}fc3tk$ zshHmR2iDKc`B$9>ikNzah>iS7s(#Jq$rXm9;JVn0ngzw$2&GkPTz_K#5`3U=Mk|Hn z3|L^)kM1dPbze0yK1RJS(mrhw35=Yb!jTB6XlB%^@@G_JP%1M4Z7Rn09z1TK-g zgI^cOd5J$!hIZh353)a7_1#6Tk);PmeDZC9mml0-GD6)Rrxe1fWa=si0)9K{0@N1- z?lslf^TS9nOCGKQeye6Yv6M#ag@$n7NCc(jTpwJY8uLgAN`9{R3-? z5P&&2=Qo*@$dMXFq79V=YiXVEKmc1jCN7wt3c(p-$XS;mjqZHk!=A9 zlV|A-K6zip#lG0{53C=)qT=&l*HQdpO3M)k8_Lj*!}|nWjzH=!Tf6qfoL}R)llH+Y z;b+_uPAJ|}7$BD6di7EC#Ymc6%_dm)yC5HIdZ_}8=O0-2|G*|U2rccwvdnk}xZP?Q zK!7kFZN^f>Pc9fW%Z&`O@e(?|5+Il1iulQ~!E}=cCjWq0BTm-Iq9IGCwsJ?ODSodA zEL%l^wMnCbw9#ER%!7LC-V`h;u7PGiK13i5OPO{n3hECCmTS0GZywz6DuEBiNanwA z1a#=v5>iH%B@SL|VbL7q(Zq)H1W19n2LloY2+2Ku|G=8{Lu`||UdoL|K^61LWpObktVDP*I&DuzPY(9_+Lm z#VbKGeR@!&{SU0yvwHe~bxhit0FS$z6|xwpPM8+bqX)@>7JzAAN^*5Z>ayst3GiTJ z8RTtn45d!x)O8qS(+-$pb+c)1xxveZ+e+d4cUtqvY3~ChPMOTg*494it8GhxwO`Ox z)7KyGQxSwJ=F0;3r=JGqOCrBfVC^?TbUMUAAzz#cVHj;o|KWx0pKKi@dVkP>WyyY} zyL$0%Q^YmNe_?HTqdCfw?q66d7B=6TP5KwsPM?}_%rFY9=ZGLv*$o5**0VNUNSPu$ z1=cH9Pr4`SDX@NH1CKm0;-SF$;@Nj5Iu8o0<#?D~s5s}^P=d8UD!Pe9b_Ot&=wJ)% zj#MUm3P)Yc+NEiWjf-uJxnbl2%!Dp3y`~ZFS4;pvVOl^=0`ZRWSnC)^>GIp_s9{kL zCTgNjEEQ5Y?PA7m+N+UR(d#5~pWani#)c&@>ly|Ga>mhwAb-YSO9SCZ`9c$?$5$?W z>i4%!OQFCT$`=O=wC!OzGIxuO(?sOF4J;8-Uo&Lr1><2Lt{DtexikUjJ*UmyL5Zn^ zV-TsBR!ru2eC+dZ0T%N%))Uk+YV$j75MiBb85^&T(nQJ6fq2hH5--AE14Lo?+F4nc z#Cp*zxS*S79JMu~8#zB+eOPfyfW+KXnFJ3W)*p{6Nx-{lL7Z_~S2~jf;mdRb+c7-g zZYqu5E?RFA$n^&SbcG=n;B4E&#g?^mmGOKs62=NTaiY>yI$Pwp|3y>B+>ffji2?i_ zFj%3qCl-3Xq(GKY1}={e$P~=qiFCTbA&>IMkDpOGjpc!E7!ek86znp33lkwr9iv}H zM@_=7bD;bYn~#>)5FogQ0q*hv1{Fy0C2sM?mEUiiaadi_s&xAGXk}r-8wLXE{B_GT zE1UT=mQUHdQ-{&HAvxzX8QgrSlsCJYEX4znM=}f_*x}EhNEnE5 z85w~$cBb=T*XOxOsX`oaMhV&;efcfw_k9a!`K~#F9*w;bYehOG*j(Nc`4D?~uyjFh zT#Nih0+(PoOWeQvAe5)OIq<=-<~OP?B_Qb{^(BBz(HR@g9d%8GaWTxv}Xn2tg z4q_`!Q|2E?bhRPf1rwn8RXDYu0Z~r3<+0RJ=I*Hgy9zy|-i|?)m_KJJta}%@l^C^o zhibsxuO!c#_1MkoWen9v5N{&ZP7f(a^pnhw43vd7yW^j{jIDxF5>`O@(hzzyGLi^9 zvh&5Cm+=LpHew)7Sv@Fo~k#5iI0Ppb#{f zKPQRm8Yp;&pC5DAdLS$q1wz+Gm9t;a!6dQ}p(ZZLSF?d-tq==roOh{b)gX^PF$uL2 zt!m>JQV^4=2o1z~f`IYm?luAAAdAeT>tWF>sQWwa)VEN`3v*Ds?Cn4tm@gB^hXUQ! zN4kq6X~j7GPtr*zf>0nZx(ARbj#M2FFt*`eKDpmC0F=T}p%nv>1gOeOsLiqGh66uTq?j~V4 zl)Ztcp?D`qfGo7$8nkZf+YJJ$V-opYL%WjhP7Y9s;#|$hHfgr7`>KExD$OiwG%{TY z`MW0lZ>T>)ANRdI*LaN=dJPnWW395fTenY<+yXd(zLSp`cfGC;pdN+DHT2phHC_j2m!vp(B9f`}fQ;NMb2#v--rFtHLagRDYBj`VggU$0IGap%6KZqp2 zqDt|1(LQz6DuS?l>MpNHf#Pe)>awtpWX{J(0O)faERx`lB!#|HL>4HA;|Y(~ z)&gGDd1$Wcj7WeTtgM_-6L`Faym*08 zpk?7zF~oekquM2_+V8Adp{qKO7LB#52`OR7sEL}d z5iG008EV{9sg2{RO)zAPE2@o-s7)i&GNzo>-kq<_9ztf?)p@Ga6|A%5b<{Z()s+|` zi@EA=oYhrcsIQ){tURl$>8RH&sxKL;C)kxY71g!aHJB(j6nHgs&}Ou&)V)4y@SSVO zrfux45AU9@?JH{J7+_%`xee4i4sktAtwth|(5h0pdMxxx0n&b4f?j~Sw3IHJkno`% zGZE1wRE=yw!EYhKZUlG>fbmO*`ge1v8J0%ZqDeWf>Ab_4CJR^)m+)X*$&{quW(od|b=Yvlc~iq!TR=Gl`|~a1!P>N6<;q+#&+v2!vuR4g9kNwfS?Zfag#F z>NphKLhBh_$TRDWTXffeemgYNvgYs&weSR;m~pzW2?AD7$t@B&(*YmWY`YxUhV{P1 zuuFYC4l-+wWFeS_;2_QBFCJ&Vd`);6{aSL8DBx$`7VxNj>!E?eW#k+ZYG#fY0fN++ z5hDV$_ly9yoL*7IyrS-s0}0UTN47Uqv{!RG(gc8iBB3>G(4PPh5=+lx0h}g5>;VYD zXVlXeI)hUw(I1NUGIi5OXMmZ|a+S&))0|+rc$~e5I0{o9 zEZ=S0ckHSXBUp)UhD4Z@6=buDW`W4jMs!#wGL4uZqpFyrx~iJhoqqw+=peeSG!-lI3!!w2cr zX_VDUbJi{HoeAt^ukJNXyI|n#VO-o|cC*jTf-wO{Q-GyOB2bTL!f(j;`Fr=d@d&Yg zhgTt?0Ztd6ppZ^d{jN9r14jhiecHhQOzm#Jq=Mv3FTiaasye8R-h>uZwy( zovG-gCY-25A3}nh2_f&|M&378j+~EnW(`v2(VhbP;ZBIrUce%jLJh>oE^J|8^cwBh z!2+lI0+a>wF2Ee|eZRlloVJz`I){0;OcE29rQenMkag_?JiVM*!0dfjlV7n2AChjG z1Rq0%_))^KNV>4haoY4Mdi9BTMz&L9q;V`)1o5?i1Gn&>2|X1yxH)|i83R;t8kOFf zknNm|4PaB*p{01%B2bme4s2@CQ}?e;jl@qGtFs$+-ZbHz_TQZv5}CH{WV3o|Z__#L zm^J;aZ`$cGt7E#ov%}0ym6_1nGhWiH9*<|d|IBE9oYA134c=l7G`V*7@vKU~>_OG+ zJ>HrqUc>w9bMlOHu_kj#Uzig9SSEj&3o~SVfC`}uvK3&aQhlp49)A+P#<+le6XNnI z--NA5eg3{7<6{%#6BB?PH_Q)*f$tFL8s`15RvPA>EF?&@?DMi{#>y|B`MN%p(Ce~b z>GQGBCs=x^rPd4F8qa^zh7#x&hcqX5Xu<(>oq+k*4#>BiU$}q^wPbo-Gm_e^9e!g; z1ATAkr<=ezBS5w}Em?{FUiKH}t}marzJPW=y{@G5Be}V&z6cAX*_K9rG=Z1Pj`)q! zJwSciH~H4-!1%xjDGZ?xOBaMO9# zk942B_0yzsCy`Kl(%9ovu?NUzN+A3b_mG$$qeRmpOAKUL_IWce!V?dXU^RR3`*p|g z>#cK+TZFFxD227FblB;o*N00*zKnOV^vmXmS!Dm4Zu(v#{S%__@H(-x_%S?+y8ju`c*W9gsAz*5oQBtk0Z!06jSi7+x013wo$T!YYw zBM&Wa9VYM|Xx-l)WJG|53Cm8T2%NI%1DPZO+(UNc3E*f_2$>~w9DE<)k_hp^!*(dk zpB#G-jxo(g*3x4-s5L4eM%eN6@b>{2OEW3EC}au)<6zCQr;FyNLibKz=$sTX&{CJ3 z7L#EmPmVIkC+y9}-8e2&45Gl|nEM?a;|48N!0%W05jD+M;)uV=2Ee#dx;@_Ct>p2L zo4|R3=A}Odez@ly44@yx!t6}N1TyJ&ktO|<|DWzFr#=-FBPmwX93f6xoxiUgGkR{} z@GI09@!&gXSe72R8~x`mHIMC%Q+Is)gl@6zu1kM9??pwP8+&d;52bJQ7vI>wGp5IXAHr*Q;4vYk z`sC_kyF;&;rw;ED9G)Ne%(sz!zxi?6ANzgnj3z_)coh8>`_lOnrEZ=E{v3ULC6SN! zG65e)hu?X`71(Rj;%hkvh}9&c4ciyr^Vyqvy3qOg1${{x-uYQcQBRs*q9l_mho z)M9C4zW52sK>9~StI@@G;GDV_;_ce34mz6J(gi5-=%Zxh}<#FtCwg1Tt4h&slKB0h< z0O+Z1#$UJ2a%vYs(7wP3Od6~IlZ-Yfu8R$Ni+-Q!wFB#Ygob4481Vnt=88HZEl5)m(^g~2#%<7(0eLGjXd2>{+Pi4D^* zZw=VWqbtg**9DT3KK7su;oZe3NbwnTl3i1iEk1L!9^Rk6n(FZkywPNl3lZk=csF zyW?a$|CEt^(l}jECZ4ApN!dPrPooU)N}UVgNKQzEFIp2fj-Ql=Yo^`ySVo1S5--I$ z6B5xq+|k$~mN)F$FK*-5NZ17K>as5S30Ry>uM1n%9viH(N|=>kVaS2(&ygjj3a$wn z^bclVQ`h0iZ76^69IdA^vnzW!rRQ?6IZ*3ng=xTYDK9nUpFW}_V9k>*kih!NOcPlT zzyd-dr~LZX6WN`Q+(dr_8JLE&dKZDK;?9LOujao4S0_g(k4%6k3kG_Tat}GV+!QAZ#qIAXaPJ#?Sx;(AkbA3L z8ef_Cm54q12DVV@Q#M`2O&0qLxT{Qa7VlYMd{%sxRemU&%|`t|OlZC5|IwXfLEMiz z0DE9m_aEBmQ;DQ$!3EFOK4564$`~Gx*xYnB_v-VqZtJ*yL!6YL5v6IepatTL(v7)@ z)T#^!(nc-rT%uBQDXW{nGjkLPCe2J$$7a=PE?sVp_#%1hH`A2Z9w61RR+poGE}j=9 zn4-5D!<~QvfQxr&RdH0@S1iSW2eRoJU>B~%M|FvQD%Pzb9-_?AMWdB7Y6eodz{yPO zixJN4LEy#2$ff+EdI9NtCJcME5P-H4Y2A`HO-SrCH2wbY#ox9qR4+1~%soy@a8!#0 zbmG>vMF$uu18(#Ys}*al5m0}QMVfrU%{b(1yBQ7L7Fm{?`_*N1I%?%F0{TD>BC!y_ zI+6QH63E|V-~(R&JJU3&pVh*sY({bR)zxt66|T=}4sIdBor6#BgxY86^)8~Q+Y>z4 zFEFV)xxT88_KTPv&ROl>zRy;eU@MNHOLVe%Su6q&O1J~_J1DEFastS?sbr-ThiY!< zVq-slp5vU^iCwUTC~*WJe|zN%v1)2w<_LtUw@Ws-5&LOtcEKQibeGt@ZI>C3_De4+ z0q#1|K*#ejCQGJ1B|qQv52>zvLe>MrTLGEx&z7cWKMh_Mk#~MTe&ZG+s@!Otu&4G| zZBpDu`LX4l+J|imCQ`qHhHo|9$^TAsM_$QtWJM~d2p@hYsQ%OFE4NGNZ)z*H{ilzD z`-3F5ibvIsU*$yhS3jY4Fu)iEjVFq_l~p8rT%FyOOd#r1UUY_`FW8x-_Xo4RTTHX) z?V5amOuR20y=I(0kAF1Qq&pOni6V6&=;#`GRq90{9P56Kd^G@MEh#HeSSUgBCGYV^R>w_EfstRC>OgDLk=XQ00OWOAdFG%gFJwK z!F*CIR%tuX#=hz4g#kg4UFukFp6|5oXzGc$Ujv(;moq*eC|ljjz^avdE@w7!9}u6T zl0eMORF7As0+mx{#}*5}#472xQWuzo{Cw4_JZ9jym!tI9dt`<~8J+K;g2EY46m#PlKY@G6EtNOdy9GwA#}Bsk{2wiBwwfbU?Jn zl+fG1$RJy_*V~rNa2;G|?&hDZw5-VGKHXzlkDhl&%x&CrqBO6WFqHRXAel1-(60lQ&%t`UvBh_JXUXt6NO zb0TvY#-M{p&yxjr6GnhF>31<0+AgNFOvW@JW~(lUX4eHfN)=fq+X9NCQu9xy=6+ol z&zov)D<0kh%_CA5-+7n7K{bknQ&30i7nY8J2##7z((j2gTE$BhvKgaHhq?In+% zD>pMe{mus>uFv}?3uqKF3$tp$ACvpD3$A)qrh5wyj20w2 z5E`>EJq#yTvtfDxQq_UEdc(K@p~8X4wAzR?v8ZLe;)#KT^#R;L>V2?&jDr3%!9h;t z!FZj)I4j14xWOi@etg}t1oG!-qSD`51BD;h~aZM50ifn1^9c z%jFg)HunH3`v4F>R*MRSkKYB_;i#juV$kCt6&=>=a_D;D7dN<*JEHPDTksfkT~C^X zUDvSmU|V{JmV&)eaWUe0Qm)}@eB6?vKS+r`tRU$$Hi`z!FAK$U>n;f4#IOmD$S0)@ zO75jxv9|dk;p{bKO5{jyG#E7=N=qQb@p!{dIi(A07A5Vc~0#)0`UoP_~J@u`opm}z#^s0=*KT2319 zNT~rAfPbwbRcZWKh5Tl*!SV@JnJcAFoi}T+VutgB>b2C{b4GOm%y=PyFBa4)$ISv5 ztNd)d3zsUq1U{ZBoKShnzsPwN$;*I(=7r0HqYaj^_~DkMxP28u5A&`MANrh%V+RtQ zT{IHY=1IUm^M0sQHq`i81*8t!4F+Ll!Ae*VOML#4p$ruPRKlpvkc5wXbdBq}!E!rQ zfH|{{emnUsGYv6k{HFlyx-59h=tHqHAc#X2f=rZjQuB5#YISR?c=h4!4al`f6uo-V z9@mHAR=gu7e?xdOR|i3hf_gIM#xbi~m*FOi*kBRO){Kc>SQrB;u2nqVfT#^nMf(s+ ze`m@4Nk)ySCVl>`Y8{ShDc~+;j4z^*WfCIbHyV=*AW4#~`VXzRS)mC#^?2L2KP~AX zvgH~c1Yl}>=dNW779WVxVMvPivK1Km6vOHz(1I=crTTVRHOWxATxdQPYfF))$J*2; z@B-u*g<3q*FZk>0>0h?atVCS0$Zf+sWwmb^j>uPh#X>u0EUS`yCP@<;FUMBV!dd|! zV{L`+ZOx`1WYX@`ztN^FpuRTOl6GiA8-x4QVY`8j^#a6?j>u>K(JzG?7EId~>LQDt z-gtD#P&}>wxJ|AkUH{3K8>RGiWj`3orR^%x87kxTtG)Bm5MW%mSTXi3%(Qjl#&^|`4nqdjT}PcYQmoy!GGy^Kz7_f1v|EGiAJ zYTFukYE08?JWSvj&a3_06#NNKWmG@{|7d05v9N#FH}FCS|1$Wq-3H!1Xyo-9)=r+} zw>mH)i*dJtak}OR-h9M`d+tv72t(4ydxbAUy|su@V>bcZMcaaO7o2o$f*v-O>=Co@ z_TfV0`N%lWXyWP%f4Y}b3USl9rn7M-;|)dgZ%lk9M*-_5p~xJRg$3d;(-8a`8oRu#;@NW>TR)1Z5P8_L;%T=mL(D&@aPX&<{vzr z%#P#C?mRS8EBlbZO>;hF23!9?vu*OJ?_4b_{oo5pDAPFohV)lsxeL>^~b`G7e}tKsTt(Gz+2Efo*-Z7w7_4I zS+;1B@%$G#zsMTq@oZDl9)`FQVHlPXZ+QZC`Lc_6jTuX zyWodx9=B~m<88vLW|2V&j7Dt1W3#~v^>{Q@T01MO0~`<*@6+_nx1^7J{}6}cO+FHu zlUC^W63&O%R4O`t`aWU9)3;8jK>MDE+aBoZ=h1w zk`-^{@;-Rz`zh;-r}=^19*5Trsr6m7SGnoBmEF3Yk5|n-FHD-(MuC@J%#C2DIRZvjQ15aZ)s!iHb-w^pAFk6Z^1P0#RBj4lFZhv!PnIrG|D#< zmp23|GvApG690Cs)#7pk@%cw>*9fQtx2}Tn+8!ojg96y zER`emUDhBj`^750AfTsiclb^KbECJ*!Yt=5p9&CZ&cT7sP*egueDFVHS0i= z&yi{3>c+!FCkOPWgNLmnX|xl&S<1f`s4SEY z<$?~*Cw<0_e8$Oe+2P%;l6Wx}0P9A)qO8XM)N5pRQXyD~{85njMFYYp5 zx%cAQEc`P8k&1tNKYZW{bYUMDP~{%I4PxQYKm_G`vIaxKzz^CJ@Kt}?E=GLKS7rCV zLX{Md)xMiJxO;M+B|EGoCxa$|_f$4zE)f8u1w)wJNHM5xiUddAXLU!QH;GBiA~%dA z*q_Fw6u7y%D>RrXsFy9}xhFi7d%>pFXKhbpq(I(%qS13-bgWnL*l51b7Rw9$M z*May%rC~nTpS1&tsalH~i>F?P7iJpmUIuO%W=qTwTn4hGy+ayjpL@-=`feOaFSG}) zOqhfp$$WhialDsqdwh{ZjD<4G_?*Ztl5?WjFZperwDk36i&-}LoXY z&y^2W)gD?l`$d-@Y|g(7`n7$oa2>K@i#gAOH#ny{fG&aFfvi<^}i|5D_|2rHOpv1)i}C zF}=>hjE?IV04SuGS+CG%{Z$n-+jt2=eJj_1QbSXkB?Po5)zxGf%BMgCG?6G>)GcK1 z9sXO(s~~AYsaz&Q#KCTF4&s`!I&A&q*g{lQjX|BCrh!#s} z8B}1lHXZgEyz_+;!U@M_!0d6_Ncc)==H=uPyo}16%dCFIJScgOX1)H&etY&xm?2K4 zju|;P*_*To;qp7!g8}a`v*_@2zcmfhN{%F}pL9LVi{b0Yw4?=l+?+g>e?1q|FL~#Q zfhI-W@FWvK{u;#u<(jPZO_GGQ)>a?--4!(F*VMowIL0#or=M?;r`TS^Z2ECAaSw`Y z&!kedA_U-Q%EH-}AL_nb9hhDr^SPJroXfegwRD!-^)h!p5)u@J)4j#npkldr3t40r zd$*>q7724 z4p1;?c`D=4ch3&lIITt-;1azsLM~ST=vOS34YK>3v93ZG$(LXd zIdHSo(-K?-gW(|6(Xw&gmCKWM;Yix?Sg)!AFi;$uak~u1u~^E&_gj3_(;`Q@J%U;( zsVm)VSsXT53qcD5#T`6cIg7EeXqf;}Nakem>J+E4b$qOsaSvzccuxn~vqSvr1kN`o z;Sx`Hre;J1gLuJJ^_Z!X0?IdGQ>o-w-Iy6XwYfR*yP=&xEm z<(WMZM-Nity`?}!3k{;it`{up2nketSP7s!X#$R`1JHc0%Z^IPq*|~t(5k~!b2wF& zQyCf*T1;r>xghf`a2AT{+@>^2lTQQN8Wg&OY+Zj$w`8|9-lCDTlXjbFYb8H?>KQGG zpT98s%8#`vgdXXzUq7qywXJ#UlcW=fPU9U@h+3?=6lIcZuFqPmB_rA=mqYT#GUi2V zp6*AtORpad2fld5I3eX>zx3&2_RN(s^(}Y9hWY7kXj@Y}+}l;szOVDei_}7Czo6f| zpZBaUcKngX-k<#ZT}8aTUtPvaLq}~UE$Jd_l9xFxF1Asl7v#T4ANZ`{%Lt6-s(g9r z!a;134P3YILD8UC@25vwtuH&*Z+s|BI^&>YTfK5eK@-F6nGw zbaRiXVB(P((w$kVtK%7b7cd{qkQm*4L+dd ztD%{5MUewdPZKcfUJZk-Xr1oR2n3?pfq92E#Y}S z?t}EyKTe3yAs)e8ne`L2YX z9CZDMc)#E(RfmhY?wHvw(-3-N(Y^q^tuKrfq2LpT9n7nn+6=vj-AdkIm*b0O?1L+sTqc*EO#h0aH13SMAxvw%61mfB&WQc~vVgHb9dfo2) zxd#hJk)=)G zbTn1GI9zKUT5jx*?b+;L(W4dm6=MYOM^$-rc$3SUPDclX6WNx_7-GbAzWM%1sx*VK zhyT=R{WY0q^<0pxt+s879kYB(r-TElb#?Z0XMdO&K)`V8TvSM!DA>IzjOF_Y^qDa4FFv2 zdPh_8DJE8OISFx~b-j#VP;MwoAoh~gv_fXuz-k&xCjK!Js2t4i9mh{UgTgs+Dta<2 zG2)bBa?mZ7l;eGsr)ju(7^pRsoyOW%!01ORFDOy{T*GfxTKwFtb$ACrm zhSin3=2z)^c{A~sV0gZ$M~4QeQvFz^@thik@4dCLib#+m+L0k4$AXs=bU?LpLX=14 zUNWZ#S;eA_LDEjKV~zRrGJ--gES8LMrUGDdV2Zh>isoD0ga z70dFuUSp|{pWu>L6v~wnQh*d(GIe#+skrRNe)&#C<4qwY!FBTh2o;n73(~WJFZtCZY~lwI=I0rOi38g zWyibhI=!=+NAX%$-5lkXwb9Gk+wnSg-0T@`^KPpx#lw1rEpc>Cq(;{QDyxR`ZSBKvikBp39rr@9xI1oTj z=n@&1{UPs+4F8dyU7R6!eUucHNt;2p6Oge&Skx>MaT#LiR?aAtz4_B>tS8;Aw{Te* zc3tx0;J(g>g97`bsP2s@GBSN_f&`91J87k*i`)>c_S&1CdideA^23?aPMR zMDS{27ciw=sRfze)w}DXx)oM6bJ|Csm+i^VIRvFZ%Hj-Og1uf>#rVU&BKnHS$$U&( zX={&*d#?|DCUw2+yrwnsad(cfv=|ilms`s%D@Wa(&p<3{W}KgTf`x5DppG9cJ0YxT zanF$HvsHFzJv|79&w*LWvoaqt0Vr0J%Nte7i~#;@l*PRspwi3BMHlhGk#sqocGto6OP0e(SoMB zp;R{5a&zJLGR=f2MM-<i%6n{{8w1uyTEC0i(gIUcMz=Lb*Y?W_UFvwIl+KZpOlmtOiRR;pkN5md}+bKC7;Tz6E3RPS=5g z&GG9^Ew^}(Rx)szd2X4+4;C}R4B~aex5{@QNE@+PI!>e}6Te1Zr3%7CVdhTCPldlx z#4Rgs@PTgD6;@$Y8iSs;;YS*DMy}L~T=n719`n`~Qt5g!FVY^prr=4?7n?0LaXhN)5LO_Sy@$9_6!K`D>+wDp3x)308Dk8J65DSK z4Ix^uzi+)Ce*5p}?H*fZZj3p-*G`UKl>v%%8&Rk#TmUUDFm68cg1jC0*a;um@)e&5 zx;U-+#`M(9$(o@M<=RkZp0HC3p{Jb3PJc+jSW4XF?RDPL+MZXyi;dw1hUaWw)=6xK z)o!a^(B@H_D;nDGXnHZY)||NTa<1ub;s-ghx%q&a*>+R=Tc`HG3~fs(85U;o_}13n zt@+~s(p6EnQf)Z|aoYOb=~D`r;~&=JBF%w5b$?zs(Dw&Jl*T`ud3(UUrkt4~b!_LP z+UG)7(X;hS&Y{b#>fxi2Kj$KUDY>0*dpF+w?tEn~4>kxWhjOyWkL1d<6CK-!HdUv5 zx@^&KKP;k;5B!=29(PlFf9zwC+9$6s5sQo2pBE+n1!3~m^Fj4S73;ZurTUIkeSHFK7bV?WNOf{BP{i^!s~Io$^RI`n#N ze1q%4E90%kM1_1>G<5) z9krDxH}G<`RCE`f_`Bi?`4 zw2KtKPHtv7OJCVN{6#x{ouYEz$E>4wEm4=gTlexlDh3;BhA)R)NmxBt(CnQ*x z5mE};4(EJB7AIOz@7i6~iC<^60G7(ryY^|Mctsu4S38d0+fGy)=g4j6V>U-VeLJG> z<$~OH;Xmzq^oy&zjT>~^O~uAt<-5DPm&e`D9`2_-6+U|&@%57Z?4=UoePPS{Nr(^c zmd}JA`|!cnD8TQ=cfYh_M`JgSMh5ynyPrZ+jv}xU)v``kzylQ$0#3x7Ha7pvZQ0%w zBC9=6kPeb>zG2Q_No!=4I~5ddWGJG)S<=mdFCP@*4SIv2NkMm2P8;;<(x_z^RZAT^ zSApF2fNw-%`w4f;^H-%6ZOwpLut77!GR*a3-@KDtl4*|K9k(3C&5!SfRXI~QWW7(6 z-FIraIU>YV6$RyGnBBOyOk)6fZzNz@Q@Ld(W>`k=!B=eA_gP^bacBn^>GI%ypf`e8 zU4FJ#@?g|)*a-(0mE>Jdw@1~JS1=$^nwmG)k6X&@HUc&O zIP@wO()q1dC5Q@tn4yl%*9Ry=Bs3UBRqo*JF@4rXAV2yDe*99jJLW;najvG5xsoL4 z`nq}8<=2vpV$+P9L?DB(Xse37iB~*`(YpVdO(TPidjmq2=?XV5?UN0#eUg(9J;&r3 zH+uxVzb)*B$6D_ofs9)pbN|NyucC5b?^EBj#D6pEtbLaV4LV;_Bt;+_W&)T$x!-l1 zYAa&=KcdH4HaDZV3$9&!PH>WJpO?1TfAr$3f+GZ-LcIig==wTFqFDh7^IxcfYGT<2 zH0Rax8DkB#&`bS^?&JyXOsN^o-jDC!GQb#guC`;wYkxC){r#FN(eVN-(EHgx;ap}k zh`h%HsdcsPN8fo_wdpE+bjwj_CrLuzPEh$q{nr0v9U{e)^#Fr8Oq1% z6y>?#{(Zw&=pu4_W+aQ+Pej8M(4i7k@2`l}TX{F?d*uiqeF8|6$d1*gHOW6wp=Iz4 zlX=!z>INJ#G;VMQ$)l;;|kwq}` z_tDa3q+?fsv-xWDH!84MG2dGKLaBX8v#=BEGVHWfpMqnuhOODE*8QnZzv9waGg!-K zrVv9HZe(V^5R0W{dGJCG{af?<7qz)o=!W{2f6}w>j!j1i48QZxZDxqCqme1pYqj)) z3hGz;jDdTLTtkaHq<)OzTR9IXbpOPyTeg3V`H!Lrvlt^0B? z3Vh9z`A2mvUku}K4m(vjLJI6XEeB4D>RW4FGIUUUUn_ahrbOQJVfk_QYeb`&e(bpiyOv@7>6$CeN?c?@2-j} z&W0`Gn2wz2Qi$^~gY3vl6Bd5?TSN)YTPCM)ul63~{gupOFI2kP+S^|G-zKk~LrQ_K zZU;Z9G`W~`^38*|4=;NzCVy$YNkIym)~3WQ5(*W(AH7OW_%Km#bHVgd>gi9f?&JqN zx|Ejur9b!NPt&(4NxL7Wu6aMMJDc|7OK<6g!Oq5^P za&*tU@D48Y?808^u$B-AGsi1jnnE*C$KB%KI39 z9|zoIlUz>G_{D^JOGi=Q+>mx6xUfoOwxQU_-mjp5IJ`eol(0<3`S2Rk!^HFgB2%ZRpkR-=!R8~CzP`2DBC}S)CaF_dV7qb6ft)m_|3q20FRhgs2W`ML zYffgfs=YTs@QayN@^fK%Mc-M+o3A#dbQerHA3do--Mn%k&-R8;ZC}$A6`YW0OQUsr z*0*1HU?kHR;A|knP9-Ul;c&@uu$K?yv!YjNfM`|3{A2!Q5N5bV^hZf2f6MQtTKQw6 z@pm5|J^KBH?-$H4WY1|B2;ei%+{?7=%>;RV95{Hlv_X5%r>Qea*|3v@!98J5+weZslvxwPo!`&T_+a){#Zg{hE>L^BdWt& z43XZ}H42NRwIYiM&lIXi2Sf_Yo@S1z_D4jeWbLSf^R5^dgMMWA-}!G`Fob%+9Scre zEIcv*=AK4LAB62Zp2A?M;+xptuZ0hbj?=S2kmo9v^-$4uBC=~+P$tg`l772ZmGuX1)*)pJ32hIB%PQEtom-INUnS9?EOcI;H{w;5|I$Pm#P+~88MZMyBj{QgX zBQqY?ohzJO?nh@g*LdEl*=PyKn)d1y^HMrfakG@~lke2Whi$DdtdFy2dI1Aoo#V*X z)Av8+2*Iy+u5GlQ{r-unbziCaW}ebz$oO^J@Rr5e=-Z<|KZWAnNaJ37^y+-=>CQ%Z zI8BRuSQ{~+lH$HoMP4RTH7|o4;%>#LWgmUp64WuIOGvz)A25*S-7P}+-;vmluO34x zfjOa3Zlr@x?9Z!w`s-kBh_?6fJ$t_mXKz>Ha@7-}S64~JW|+B$=rezWcD3tPgrUX2 zxbm_#gQGCY+M?!pm3;d(tCP{Xcd0L!P4_t&phr^sEM04ngZywS5Ic`O%;=xEu?7mlLfwavPX{e#C?m^indai$%thDG;JJZ(E3$@nr zo^y8A>00G5#rC_`N(dr^_*c|Z-|ye)5%hiTMtI<_pmE~IvuIdC)nFJ)v#fJ8!c@Cv z`sSMM-OjO7=d|m(*Ij=;>za?R&JkMEwb>qx z8yC3vS44 z$u8yiqi3eL5Me;JzDqIE&%+dFI%y$Y#}qkNj|03JscV#pslwBn?C-+oSKVE0l|8Bv z+IKa;q$cgU>-td^DmA>rM6_MvIng*qk9Y?LW#Vs9E?{7z3Yei{Yvb5=)q$lj`oVJo zr0;as#V>pE8(duKxJ+5{5^$}5xd2_+i~QJ}(PCB#^mFfzbE`i61L?&N^zQh4{;RrO z7gbObvzZiQBcFIPIc%BS9;sP?JX4-?Mm`F3kV^qoE^(oVd}uH{YNBKr3z&i>IM*a- zSR9_?JL5BivR(0L^xU@1`BNFAAX_quoxq41+hkF&>tkUV8EwU&?M1;D4tN-#NvIdA z$`6m9Og3GVNN0Y`*hbH-XU9k7q^{=-(P+vt&n;bYt5C_RPI=9?a1Iu90LK$$16Em- z$XG1x#<9D>d*is^JRWXQ*QP+VqL_@LO;mAoVeubD94HqA%cW=DcqL$mY*w4aZ)mlU zlJ8M!+9&^rLEyAt$k=TGfQrdz{wsDz=w0NS=%;Ti%`ULUE|Bf2Xiuw5QPt(S)wNIO zUKiGguxfshK}MPcfytqP;IMnI9vP+Q*YR4dq;~j#um8zwf+qlJS1i6qQ6gR~REt@r-`^IpkYMC#4 zpB4Y`DC@59rN$^q^-A%_EA{MHp>MbG9nlbp)s^^iATuFvOy0Svg$ttax1(^cpWk@Y zre1-!ZOqzr`LyeE*`%PFtgEeWIs-2Bvoic0VV1&F<|$;((GV0ON|eO12v_t76V@4EJ7c z4d%*R=Ezor)GIqFy*T_9#rGlVrJ`%GD(01r>#IXg=@4j%sipw#xWGZIsppb_V8f1w zE6#69GWe@}geEnxm+;oq0vsXdP?*Rx7hIspy`fq%U7|xQ=;ut^4p6N`#cURQKGO6EMEqCyj~~OOuTi( zXXCy}U)*JZRtfRX5NIh}SF-ws&mP(#CB^nE8= zovhDwJ4}gwz{5<~GFT^=@5GpwO5bzoGWgv?M|8*AAT3~lMl5O*B$0GlZbC2iR>Np{t<69LFLI6xN`Kc&xB}75KhovJ zAO7gX&w*z@V-UYaxq4EY^yWVOs#}y0gDBB=dCJ|56&Ye4IGzwQk;JVHod?Nxr+e3n zPdzN_`}QS&zZmp~7i2hU%(a3UrHBB*Tv+Jg@9v7r3^5_9_|3$SH1AkUA~bFkDk=aw z|0EXcG3?A7CMu5eLExW*$Q?L&7Y{4(513z11lunpcfCqGpLvevGFk*oDw}gm#W?4b zk2L^x;vc)~VjKe2F~*C0&F=iW!U;cq#Jno!7UiZ%aPx=~c`njHieo$+puB@^dPe&q z5Z-_kJRJgxsT~|)$cc$M2!mlwV)_vNf`_pNZqtH^p;aZI!_ z&8zZoUge3oN)65nXS^;XS6_&Ic|nb{it1bSKDR2eQt@JDbQfRs(RQVS8&+S-`A3L$XpWkPNlN@f7xONGrxe!9HtqwEP@2dQ;@1vb~ETOyZh@R_(UtX`G{C=Fiu4Q=PZcvPHa#pXs zMPjPnRd-G-dn-K;eo4$_k%Q%tIaoiExul(()OdI=`GI@Nm*NyFg7NPo{Sf*Y!L>72 zl2dngOK%FNMTVs5Ht&rtX%$(WslUx9!ZJKY;yYCVd0rD` zZY$l1J}l62_T4M-6`l@L!CW3n;8T z$TW1X_3K0HKgl*v9LZxb9CBM!MY3)E^uX%YS~Xgto6$Ad<_q z##deiuB!58-{e=T^1_#)GGC}8D8xuGG6%8PR4*K2&Y9XP{%G@O<@dD5C&DV@U41({ ze4lWOjBzjIl@!!JEx7Qt=6On?RR%tqw`i^cv}Pci`etgN-rD^=9-ko-xE-fRmS_}> zI`Sv@M~BSNouF^ui{W`GT2#7<#R>{kQm;{3)-b}WHzMh^hW%MOW*i(oUfP*FhIv_4 zEIK~tKR!hp|1>{7hn!gPpZHNbvGHQ!Kw>iAbJ8_uvhc;^7-EVmV5%Z(O6A3rwB++? zkLSKw&s7$ln{iIZc}(kHn&#HQ{@+-a|Gx+(5(ER;!ruH>tY+KZ|F2l>Vao{a&jMua zYi;i|4CaeyNBqq}AJmKb=^H-( z4}y6+h>c(xF{5Wn-HmGQ+y4)O`Ji>-&WY)wnH!oK6J7st6ke`iU{%^5b;iTg))zIlG4F_wd>aC9>4Q#R6sjGeK4OQ4?^i#^o*jM0`X;@Jg zTdW=~Q#p2OM-}?)k-H6V>+3J1<091?#}=!P zJbv`|if+$p$djUs=#BI58->%1uU5>Rxw&xdKVtRzA{G7@YpcGp{Y3f<;ve$OarnO+ zY|^bx+u%MGu~TYDJJTDr)H|khvJNO z@9pxKX!fN9pMj+AYwXkmj{ygD%Ki*WUJz>@4udDtX<+kg_ zn$x+Hs7sfE)~1?vuy@EH|8tr#B$!oEDTf3Gk!pLrQ$_g!{$I~J& z*Cu`3xc0R0ihP5O^3!pX?2qoz7pvPxh?4h62NvVH55JXwDPHY0!IF?myYuB`51ab& z<22bK?P3P#;6mPB!kFQQZ}zPQ$@h@06{15^ zpKj~<9jd^szI0GGJZ1b}vAW9>yfS%3v1|*7#xb@C8%0Kc&h(Pg^v*E2JE3zY#*r_d z9<7l4vet4vmNKidV|Zl$#DBzU3HN(8eLlQpzZ_50>rOE<{G4jh9(e);e_XD?hjh1V ztr1_9C;RDNv&{`x5ADLBQtQDyon6f_{}HPTOPbkBhn)K~l~Wsab! zebdO)`IfI1qUu66?De3RbSi1|1Fj+@%+5`t+wVVOwerFBwR)iAXcm)u6B)bGhLYiJmMQJAhv5y(2!*Q4Z|`mRf)o9S_wc4nG_oj zd>pVfrLYR(Y5nrZ{44GxkR@_kgJSllMcY41?1#ay)o1cl>WsO%jk<*;n^K(3y4ixu zE5&3&QYQy>BjB8p0*yRWSrl}Vkrz$t7r!^#XRgSkUK50IuX5Ue%rc<5-9bF9b}I+7oI(deR%w8f2m^ zOVL`(3lH-VvE9$amP$rJAt3zlPlOCiVgMuS;nOEsJ!z2@L_~+M%usAhRW}F+Ngk!K zk)tfZOvdSGgI+YR0?m?{A&4ApTt)2TX*Ub~*Vds+=mu(Zfojy_c&LH3HIE?A>Z#QX zZ(vBb?YXa|z$)J$-XtC&fyS3`*_m%)`5?LmL@b9vKNog6yG0F_~$;)~eKaY;|FBl(OFRAe?5+kqQ|0FAv2L_Ff>a+1;9b`-X z)8dHPf2V%O3q)J6xaCMl#-ZDZag9Knwt^~edWN8n-=Vlr9297h{8}@+> zDCz2zkb0K#Q%~+lLZN?a0SZndKTGhp@P#heidK>Uw967Y(x*>Tk_pqS#c}$eL4P0& zvM{-q{)wG=DNv+q?YrZ86fc|W0h0hs=iCe)B~nEn{1E4k^(JLYUnC)BpBA0|vtrI} zV+_3tcu^oi>k}OSjHsDpu70jaSmvbVTke5^2z<2Y$Rv!*^2=>X7D$MmW2_n<%gove z0A)U);P0Kz=XeS-Xt_2%R!M0K0&D}1z4BfPX5C$vZE-D8rW+ru5iauq!)$HYL)o(8 zva3}Dgak~2P&f|yRfs1p%|x^H2zf+wwBO zPcrdXPG1xe5`^?hKIO$7Grwl;ABW5e!*TF1SzJK%0^kz_eKf!l^&(S*nYflP52ENH ziHty@RhZsA7K*e8LeYH&yoPoR`kO)O_}&A^E|j{-`UBA{GXy!^KtuV=vri^)M5c@1Flb0x3 za5(Q*ucb00&z+Nc4{e;IhUp`t1@JI_EOuiptb~&U5_jIdai2Pyq*R=I&0tP3M#=H$wj#fggcwEy zYu@OT#?u+>Qu64M#VvX6VDoktjaZ9JbSW7=IUZaz%JENzCk0H05;ktNf%6^YXuFoD zfG<{VxCXhC<}!gKPp;LJ^1+MkJ>3;6P?iXFI zxbipxB~Z$>_#xv!#F>%&ns@a>S~hVH8S=hON}}%KlWudqzlp~<2lAGL517S8Kx+u* zADDb1LGDOk#d(wD= z_esCbz}q({=SJcR^f9I`9PSqC??cbLm&XWhgEJC%rU^kck$}J=_>_yr2YL7Jr+F6X zhp;IaJ9?BO`} zdU2S6=Ut#ceV9Kf?qDrFCMWjD`}h<&m=6dM?s67_1N$lhpA>*M!XUj5XW14dIqF5pf?vNP%s&376zD|&lfWBXCy+*a-mb1M?|tFulb#i2ss%E{Au)s1&5E` zC4(o)`98p<6d+_VaYpd?9~)ZqcCG>uPD#lO>a)Y!Dn|72XioE>LvdQmYVgyTFc*yr z0H|z{y#W-$7V}g*H4F_-8Hs=d0OTDKw=91q1_$|Wj_5;S1Z@CUvZ*7GdvVbFVCB5B zzM}`rh&`~U%))-@06vp2RyoM=8gQ@{Cd6Ldy&dZ+=!Gy#M@%_lf}H@834}%pA_aq8 z^1@~)DrBn}Zy?)awn{wc zC<+SUR#H@a5u&JeS23iY6UoHzC-6MPQ$OheY=CQ(WN)x;XhcH@XI)sc1qd!+nwSMQe|LLd&->2Pof z9EaY|0x)E#EQ@maOtg3q7{`Kf5RD+3kPwCqfdj1Kf@li`d(i!aSa6la*y!yNi%jsz zCjWCy5#a*X93V?sEEq@j7`|Tnj31<{1Hri%`&x&%ACyNBeUIv&0fvMz-)!Iwdfq}L z#IsPaXH{~S2svibh-#H*WOMP&RgZo=?6;w1RyO$ccL)xEn3E7bK}XnW=%A)cB3N)V zaCujW7Qg%0XSDAz;r=Io-Vw%~|@AYMFZ; z{$vwAGTi30V{S!2O?2Xyw4QgThhQiwgoMzx>OtgR%FlDR$vFhX-FW_<_&u1;*Tj_p@1rZ`%o@G(dVlrBj+&4z)bOnes|K%E2B%*vb5xjuh_k0 zW~}>av@qd^wqZ0v>Z^lol|}2+eL46vp-|98L*Sy@Lr`O?Z_qQMIz$i98fJoBIKM+U z2`qNg4yB=Z9-nsq?UHd)&ix<=A+(RDXt%W{Oi!>aBj43MV=le4H4(Zf0Dm?ApU6ijZ$Jf7kT$xyX;}S5Na9aj=hBMr` zmwtE3&9gzwKKX8?6{CKgOxBm%d~A`q70twx=3r8-~v zdi)^R3!nOCfA8sckf0;i}lh$K5DtrOl$GkJ3(LGptv_J6Apn^HRlPSG^RX%W+ zCuT?Y*6)WTKG8%zrP!T;7dHm{{tVd}_XSAwdu;aDjt;1f4wBOQD78vWno3IOAzJOQ z?1A}E<8z*!Ahnoy-q#I7FLo5WDN3>FgQS=zHO9lK=!a^xPhI{z{b)Xzkv`(>_T-JY zoVDY~#cnBciD!An&+ZvZU*qDXurqb;8HCsUx6*_@@;$4T7_Bi@Sp4+liT_}egeog! zq}5UOY{BSDqtWJ@JtL~m2>#DrcaM$6Jv??pew#&jIxLU8oAMqv`o^el4*kfvc8s+& zaB8%#_vW~=#64Ue9d7!fessS-Rw0smWYCj7e13{NPzAE(jEPfBxm!g;7oLIQPQ5(>(rwd4E>& z?ea+pPQv`c*|%>4W>f#xb&r4ts zm^!&iWuT5TS5MHF-rZZxTU-sX1QHfkouojCK@g-FIE@5@1Va*-$atckAb?CGBDI~t z@c=@}a|P84PIq}Bk3~Z2QA&@N^O#7lZHW^u?;-31A1u`Q;M{xaB-ECPfLDOi2`}B5 zh^JrQ0_QeboZj&VF4gkzrLiE31}IlCP}w*LjYVckfi6pZyrK>SOv24fk&DB~W7sND zCVXNFnnplsn*!)l7#k)6$pW1K#g+wvuKjbe0gy-+(4Z6uJ_(PHJFMGRwaD^6ObC}YZ3rRQyuB|{S&g6{XFt< z=?91=ioEjqD7H!v3x6AdxPEFKstMoEf<_exRKW0oLU1TNsX+%bUa4Dd*=Vx*an-cP%A zyB#GE$-_S-=@2;Z26y?V^c@7%1b3cSntnM>pRT1EAd4?5(;*WJ5WLYz*H7U z5&Ox6h@8-bYremoKyQSd)5*vFI&=3o%xsHs@EeNz12fwR833I;4x!TDBiJwLG4kE& zR**9+{v15)Ej;tU6n>2H@s0W#LmjZW?ABWR<<9LNS)vFI#6C#}7Yr$r*G%5}xMNYdooyhy|H{};h@ ztobj3c~_2tPSXLf#NbIHBA-Wf^Lp@;IukcY;?mtndN~BVKa2u-s7!)RWS}n=ePG!{BBj$ka`JG!KxuqAIgOP zU1?ahSxCtEypm0shU7UP?6F$ zt8rp*t~K{E&5Tjl0tm7+L`R!;_hSdB$<`T*A9bN+nas%Et%unTt2^l$$>1`y-eqb# z8-8fK>umG|&ktEaO_Gbzip@B(%1cFt9v(%f96&ht36vv;f6FrRHBilJ9h^;h&Qx`g z#gQ9XnGnZOh)meCTT<{0Vv!`D*gY4+&-SNZWc`aTa3vicEe*Y52Um32FsF_SPw6GIA(Sg)uaimtn#j z2`V&0R6`LAT2(0BM9(OuSl#(9rqis>4@Dh9Z9+Y$jsCtna&11C|l@HGR(b1rc z+MDHmQHXR61LAK7+4JCzX2&v2o9LkjyuQeX%NCgB(iL0EvdBrst*fO}c>a;f{Ysk4CdOy$6n7^~^rTTpQ+LvO$rDFxOxQbOBmc^eBOgj6%pE(1>U|meBtQmk{bAwZ zNCMI{WhqDD(fGfhcOO}++>PBkD-|}6QZ~GKdy)(G=4`}18KnfLetC>Moc`6p-gIw& zgB6(eiCbUt+}|G`9v@7M9X_@@D%|xBK6&<^MNnEiUeKJcUGZ-CC z>(Vv>q?P8SIDAsB@piCs)KkPP>?f(xh`4MU%MiYbj)9kI^yKFqxV=VN|CAih5v!;H zwVEk(f?+04<)nyS71KOaCFzcn4Pp zvL<9;Y=c15lS>@^LXkiT4BsZ2Z_EMfn?xOpiOV1M$&w~Aq=4;U!C_{YcKQ^Jut_hv zW*M&R`LqMpxLD-LdZOR7&+X?`pR6=2ZK)HKrS`TDeoCfTwrd{_M~98G#QTywyiwGLD)ARX^~7Yj~OEaip2!FicqN^x|@)-U?9i6()ac z5rXSFgLOKIh!QT%R;w`tVX*`P-5Axn(+=ZU>NmSZpl--eJH)aR8|AicLqtwrirtd@ zhkrhUK?X5^+2sKCVLz2GnZdcgs$A3W8Kx7$V`Ynv=buEGGD$p)`D+CJ3m^c?FA6Ct z^+cL~jHo&UZXOErjh-*iu??Gxu$Ax*F9D~?VWH@)O=3{@(=>U|Q_N`Cade4Hor*Cp<#aSO{@>jM{ki)R206s`A=pAoV`pKN_?8{cyW==TdQ=ctvc%sz4%MyuY8ZPH)Zn05u(q&(ii)bPj`rERq)TwJCgN{bpixGB&0#A#+e7Z><#IOIMn_{l>ekvUj? zVZVn%(QI~fJ1mPNxWOt^vs8Us@aUf>&gs^15JKbIHSf1O7artt{@P+8TUa1)@-U0P z;j~cct8vGLkV?GUibi!*@%m9~%BE3ojjJlaTMyt($hEbB+Y;n72x0!P~;@@a6`BOS3v zA>ycyRMcpj8gx~a+m@VYq5nDWQ5I1?Xj0E%Im?XE@!7&G{Y;&JB?H2|;;_=a#X;GT zHF_!ALlIHoH@YKftf`hlY;{~#8YKMTQmbattC|bbZE^yr zJN)9yT;vQDm7MMNsEj_zM1D~w-o%}jwR`A^J59_Y`{3pZb>X#)0}~|F*sld<2;S`f zt4Uq}KNh(sb))OhuP!r+&tn+cV6wk2lcw!kWzoZ~knTP%zS12u-C?duwh%C^fml)| z$qsy_mh6$AqakNH`;8T}5UsLi)iy#=5O)(@M^xA$Qwoi2*M@fkZX3@Ge(kUT-VAQf zHJkp)E{61o2@HG_NAWKj&_IKrC}o5I>eY=N{@VL$smy;4L*eKiHAuF93`%WX+bYb& zRRX0}Gni#d<}>29h-Ub*`RLkE8|?_rL&`w{56L* zMTfRFr1BPZGAxET!c4NGtP^&XDOD=}u2>!@I)K7H8iE~BAGL3|fUaIWilXE7;~Edg z`#(C9hT4wKPLDz5AB7Kc-Qcw>jcU<5%r`j9H+-p)hMk0ysu0$+BA(Y+UIS$DQtd4) zGz7>w&c+C0E^(~)pCu_I^Id{7%t9Tnz-Wi(LLZc+*^*+ia}$Tu4w>5<_jWE*i)6bo zwU%cZOk+K068JXhQFD$_gTpDb?(x`mr+b@ zXup*@{Jl(BqOf5=xpmrZQ=c<<0{>8GkqZ9{cOnSTDJj> zMm_>T9PH}Y-LpM2dP6MVj$%tKl%SzOa%~c0-!f5Jtn3^tHp9T4yveIWqK-_#ODaDx%2RkhxOiRZ zPCwBkBT}$FH4P?Wwf&e$7VN4EC!#%$B2fm%i!{Rs(D63>Z$6qK+2VuDGspXlLEBK| zqN?w{((g$P2Xh3xtOvg(cU`Rc2)CU0i8jRwsGE-#XyukQ?MWs9di3ONR-Pw`kI6gR z>f#44)22vq$sIF*aWNHy4KnfYY^A|QL)H{y#hMze@ulI88Xul6o=LW!Nphmu7~~jc z@u8}+ZCnJjg2AILoh(b43MS4 zJO~S$FtJA&AV>a?qXCaw9n=$~3{Da>ejoGZ{RM~%=z8XYZZ&!C#iQ3R0v}u@JFv1z z>+nf3IA9SG$#53{vIAV;`W>$)xM7hgaJvrJpLxz}g2>?6jGe1G!hhcCRGWS6=|q`e(dYjBCvG$=z&$c8Gcz?bGk31cv;nwq&vK;YC{r`ja+dW0SFX%5%gPGPoh!4l z>GAtJ=eo{0|K5Mz*A4gmevQZTMCh#Rt63TCwEZo!rymmnd(FeN^G{FdrpMA{6fURx^9+is)wHV(sI_2aeCY z2qLF3$&r{uFHq2_arZJcm@R=FNQZ#efKa+!{e{n_35(igf%(m!`~UUi*W=9jN%KHZ zIB<+Zhq|>L3ne6Z(UvxH=1Zf}Ez5!~g|lBpFTYM&9>22urfT`^_MBMn^2Dp<_p{4e zAHFYtgs%u?S0*VdQ${PFtX8I7S7!WHW}{c;l2+!EmQxy*2F;T10*fcx;yK&2F9L9D zfIJNjet9Ln{Ey;-)#`@p>NmgD@6oG2l2$jbtp2Q8-R3V}RfVQk0n%;IkdffN>i7Uw z;4Xs5P6V4y5DCj3{e@p;KVB6{UPBbDA#bg1lLcZ=)=*m^i$?R2Bk;ql#k&{ncH;uQ z!$fz6!TBt}01$cjYE3Tr3$Eac{H-qvtzWjIP>R~P0c=S)A>l|^I9_g@sJc!vURSnW zCw~kn9)X;yhM(fk6OOF!y0xy}x~}nLU2|XPKrd43$GVQlSE}4s-Pd8-{~@>ZtiKu@ z`D%FTtI=wRek;Fi^8ug&5FHxnT6IaBbO{kn~AAVGl1vjwYg&{f$xv-ZJ8IDQeNLuK`9h z&TKD7zj|4p4|T=$01gQ zaFei*BWlTx^AHDNl6=^5;p(zW+1XibaClhK9<>C|hM%upf3aJCUD_GLT@8u96qHLIQ86#|2ET4tz@ijW<3kh1mfW_QR*1T3Dr;(4MK^DLa9M0n9v&qA#!~7I66ME z5E`1zZa)hezXpmNfkv!Gnb1V^!+=&1&Y82ol0D}WJvV>9LdSanAm@>7h&=|$O7IrKw?h3B&z=QdeS}%{Z5YnOylEnS z2J5QDQ(}I;+Pi&`O~yc|o11V9SW^w6%Zq;f zVN*)T)#GtjPKRV=g&;9tDh;BE;JoSujJC&##PPHkfgePmrjft~#h)NBL=-FXu~H`? z-53{j(H!a;^eP5(wS?G48bE5FtZ?AXvtU&O3%U@m|D z{~?&&soMzV#AaO)?NP0z(Fvl@^~i^g-`*S=0KrSWUoDA>kbHdo?syDS@6VM~^jTK8 zzUTWT4vK4_M2|LtiSv3#T}$|2E2c%fOK}HZ(9MBr(;Q36BH&$gd@#SmO)%3os80*C zpJV2IG?I6IV-ZVa!WW4oO?LPmQBe1jz zL|{9S_9d7x7mNK6Ldide#*#Pwgf;-g>&RwTlIEw-hR__t`PBbX1X=)X*gPS$Abic$ps4)f%ewz$!YF> zwEt1*^KA@6!3CNw(dsg;x)B@!+a~@UG2-MoF}T+_J0wt&tmLSHhdRqX<3te|%l*kP zhB&VgYT@Bqe#=^%jkUBOG?Srr|i>jqC9wPmpRkYckL*A(pG z6UvT;;+;N4+Usv!>!AS=j-{^RV&wZzO@C`PJ-7RPg=OJxKYjd_X}ebI``F)FZNe(U z8K{5+^T(1}o<`m=bj&@88>=O|~rn^KFt{Ja~g=s*SG{=GrsUBIH{wHRcQsIxrM z+M?QiKTmgi!ckAqbLj`;rBZ~Xl?CipS>tn6$CgQY_VhnUC_2h=KK^c^;in(|Tl-U-Af zCXH1+eQFgO5ssUcBM*nD=HVv&MNdU;f4k?;(b@ZRWOR4G$<{@UL8Gm|zqj@Q;nPMP zeOkb4Jt63$Ujc;V6nZ+60FmLfA`dojWetYfc+T~a9=$5*LMvninG=CSd-+84cPz^6 zED?&SDk|YU&kwa%IOK^*mh9qr6P1I*3Zqli^tN)bWR{)_WH8Jphexfp3oI*LM%=Ss z@5oLJF54l;tu9qHC8U_AfMxvG_m%{!sTX;RGDN*IM=gBgeks~F;xS2)eco!R)Z`aQ z_j(%Vol7D%t6V#g;0RvD1+@R%&aXAkF0AKihuV`T8Vqd^Mh#^MgKD~zf`G)hSB}1* zmiHn;#bk(33hj4L^gM`&a1($n!{A5}FjumTj(dpXh&`^!@Rat3Pt-j{HYq1a@w!!f z%DDgifnO&((7}p@!_|ca>V^sYTOMuY(G64(%7T-GJ<61K6zXtU!m0x$^hoLNU{ncR z+?L&^lSNbC?gB%IgreG(z*ppktzcy$pB?=Ys(w?i8FhFO4JTu`JM8p>UM@{(7ZNoh z9wf-mg>jB{F0eh>=4e70NSQwcV0^peT>%F6;3Sw=cSvK|K+|WiVw@TE0;Zka#q;1k zyLhjqx&Fc(d#Jwn9*;rf+!~)G6Wa%yz0xY8!XgpXCnhE3;{6-hl!oxkKbGCOv_`h} z6%DjWSY<+~n|Ac>1xXE*IeyM9!L^vs{>2ZZO6=n*cp-D7c-|czZAGOC>KrwjP{+d# zV?!_E;1kZ5k*8SZvMRZWUsAnckN|cpSq}Cz@iIYRAcf8@FoT%W9_3XsOI%gklga*m zxoPUNnnOtx>fQTWd1E`_Lm;n$ur3+remG57BqPR(w6CB(iD>6oiwv>O51#C`-|tab z&UfoQT>i!BJAht@{&MY0yjFgt<_s|4D$&ub6&h#X_i^@0Ir8b?l{Af6Q9YKfeR6UH8y?j( zcrb6~+HI`}-j;4t%Z1F)AWQ6E#>du-p)2U3-}nR3MjfBDPPdN4a$3;c2DQ$j6PWF?i%Rfvh{q2mf*@%GEbG6Pel;U~YZ1G0oi9G2!~sFW;uQ&H z@nM*9o8tsJybYU>aKs!6YBSeC_Xl~HXLELL{mM<)CH3QJe^ zN%n3%9Qktc*uRyK)|NSQonO!M9&2-s!bxlEiIGkOAd~>7DLMOz&J$%HtyvMkLTD(a zQqI3YjCQ3wZSsJ*NWs2~%4v@f_s>4w7{0W3qf+OB+xGU+AT1K8%aX&nD5F92zxU2O zPX@X>(dUT0t2uWsTD#KGclQ0;_@uM-bM(J|FC^1NIwn(9p&aZ?3=`l1z(KZtFbGx> z|K$SRaN3KI4WT7;8MJXeo5W9@qvKg0f1NCY4`=*6QzmkefJkDwqLL8RTw|WO4wU1` z2ecfz3@}_zC|AFOOZMO@ZL;+>6(MCH+PEd2X15TS5H)IDOX%SpwL^6 zXTDT?Rlef`Q3>9UUm@=NUcU1mkpQpQjtnHqRuGj)BuWKo8^JWHP~J=0-T@>#l2lwP zRJ=$OzY0nyNj17c^&&|vsX{H2wChU6u4^RqstWabl158~#$%FZZ-wSCN$XXG)(4XI zY=!m;NhfrWE@L(Gt%8bH-cB&lRj@6@CQZw@P|+!;cPJZJRT?-d8))b1X@6oER(hS6 zH;k?{zNk#ApJIM-f4#rN5bRYwwb-*xZ>*=!PRi0!-GL9 zwwN3nj`4YZy*#=8J$e5>g+qEb419#1HYx{PZyxrV@!BM}5V+K86YFWs2IeuqW1nZY)U;lKA);fYo7nsmI zyf#3_4gBM{lfP7wP$lLev0_*c5KDT&b8~Cnhp@}rmu_gr^*qo1q17)_0?8t!Xkg62 zYDpR$WG~-^E59sv7JBC{;k~E85g@RF`9Su0El z1dFf9d7GFq<)tb-uIyU*eFG?NbVzh!4sg`V89>H*?p5{gj{3aTN3UQYDiGkawK0BvD=HXK?}6GSlZIem zyjpsmOX~;%UTz6Y68u$I=4p2pJo!sFkN6u&<|@8`D!a>2n(OJ$Ho=2bW4a8@z)&bK z1m~muSMpr>SG2cX?Egu>*z+L$1aqD2l^MORS@h(LmpNvmbGGHPNDL(Uuz91X`4{wu zZ+>@IL~A_z04?73k%-H_wzA=><8^*DB48Eg0uggMy;2VP;b{H|1{iO5J$(z1!bEsf zCvv5;kpU1K;%S(!>{^{~5i6c9HPUTdnnzc@(dyUP#HCQsw-vAmlxY}azRN8L$nVsK z^5qKSgBC-#Z-@BiiZZYow3oXLjHt|W3qHV*?|PJZ%>L9a?YdpcxQPf`7I=eU7`zn< z``9Dm!8Kw-H2)=Y$%yj8WN^lQD0&t8zhZ91;v?pSQm5RJ2kBaI&`~7gzz_PTSl|Zcf17j zBo-W%qeAYnX)a9h4fhu z@pL!?;0zCH7#dT*d3JMNGT0fCOqdhjARnxw%rw-ziY)1R{lSuZX<0ctUVVcufr(Fn z(^WOiC0qanUKd&j^L%IM^|jtr#BdxP#kfrvQZQ6|$wuM8|1CC{%nK~jAo?~SD30m! z`J4TdD541e$R`csHjvnaz~tpt?FH3u2fx;vxNuP$Yz^{P<-#_Gee=8Z`_h|{E|tyh z_nR+{{_xz`IFLu%cdQvn<|m%oOgh_k)vjIC-Q>!#(kpk*95X(1_;_>CiMFK3n7Jzu zr82$@4Pqj^Z@l=`b6idOP|zKC6u<{-*=RT$8)mw4y;2SGXKSEWzTfB!-Zc@Ht@lmO zq4VQ4^Butpi@JtJ>DN79a#G$_pNiIOh;5g5g^+@GT?mRzRMj>fGQIsS@%Eu}<#Hxo z-M{M2Hg6|Vdv$Y6@=d(R^p#gXOxkAaMd)|WMu<=JutfMZ9}{bTpZQfTFmZ`XIUUV& zgivsu25z6Ll$)$S2NeF&L`QB#kH76%G$~Qcj?R7?v6I&&^WW^n>s|M>%vI`4LZuR9 zBXuc#qBOOqC^p1MhD*EA3LBzB8jeD2*wmPmBl)A!JP3kr5pA8I9n(m0VM3NTEO~o% z8vDqE1>P6Ja0Agw(x3La#U0P<1exJa^seD$(d=VEpHv z7oXQ|GGntJ$Lyl-YCaaXOE`P}nQ5iH#t^sDfM(k9p@+R4{&y;__DEZ!;<|}PEI@^v z|MkZc_*<8@{j>+X4c&8mq_zAVtU?61{|+W*w)@$`kcLwiz~j|g)_c&09(fA?-rZ^1 zu=VJ^`R<0S(|S9N@_n|<`R@`ZL`@APV+W_ype5#bGP~k9O9(E0JBr7fs(Be;{2Fk8=8qTl{ChueqIhaY0IH@{^?wP4DZzSi|7Q zo+C`8>b?d0+aDeV3mIGgWOuv8-}(N%2V_V1uJfPgTJSDRmx$T@mEB!mA|G~Kk7p}@ zjd%||@dA@ervFd|czC}F?szS;N2eAk>WG%QlPt20AXPRT@d z#=9RlGF)WS5d6a2eB917dsm$kq)1QI``#|8L$#9HR+wWa?qlv>HBRd;x^I8$O4#n( zciL-02KHm-QUOE#r(2*3@7;#Y5oJAB z6p2qbR6`;@4an=pMkQ%E0#b923!_j!iI!=MdIdqieUlWg>PdWY@*@k__`4$&`om)JCCWYu&4GC_J2Oq5 zOh&IjRd$s`-p6b+WjC86j~5mRXNPYc(sB5>XZT0*ctuP8$wDXE$5)>z)XQ1T3{W{JZN%fB$g$^9agCwhUG?*bzTRlJ#Or}Mpx zmttkaJW}rRy>z2RH8ySdr;wOq6FUzvk1m2=&G!gGIu$BCur1s(;cjv3s(X!9;n750 z^D3re_-6-8(S@7ZTD9#dg(g+Cb`sUM5L?I&4-rv;d9nP-U zhZ`><1`=yE0}2A07EY!ms(Vvfo{;pB9|ruy0GkAb%R~CSgoVg{insFf?k~YxCA010 znw3vmfW6&^4&)8s>uGYAKc(5FNGCczn6xv~9b9Vj9p7#ECQ6E~_VACK!(W8>xo4SQ z#eQ}{Z9>29FZg2EKbZ{e9+|t&LA%eFr)a;Ouhe-N=J3<^yS7EYM>wqKm8*q5Fbx() z65W0^H%gtFI`97kFo0rgW@J|y0yJ-(n=WV8|Ey4cA$caQ`IX(#*}b6{TVOc%Exg^i zZRW9pk*-{)#p%37s>qGxZ5RO|N@_d$sA%Wgg2_PlT1rTN(|4&G^v{3np{F<6%uCWA zqjv+OVa62E4X?iI1t8fXr<_4^uZ9nR$=317G+~vbyd=Fp;h-n;4DoQ#mZ@FNgV0W2 zY-{NLnd;m0h5%_tg%M`S)rtoT3MUjBUe%R$VywAEqB($D(aTdoszpQ80WJP=edHHF zjo(VUz)_Sz9K#PZnwmuD`!$O`CPhF zuN4K8tQO7Z()eKTkn*wci%k!83o9iws~N;!-&?&f$_Vp=TQDtIE;N+ymy@wUu=ORN zZTrgLH`jXC{zc=h&?zUg(x=H?1{4b(1Q|O2iK#}-@WKe7XZzBO!2+s7k7l}?JHpPi z5h5SP#3#x75+&ZWO844C-IA1UC+D)gHo)NM?n6@%U_5G??erae!jE){7DqNMbm+F0hh+2hws;(<)On6Z1qa{pcd1mOVTF-ks}z`L-8KL;mT!+tVpSP+lTm z+xj79IQrXdPaq6<%V{+7@@QQXD#8VVz1wj$mDx)&z6QZQ zqU}!)mR51+nd2Y273>^@3*N(oVx2QqyY$vuHC(zBTNXgNzA%Ip->+ll%;(*=#4=s@ z?0`q8V{su}_r6x0eN^MYLndIi(C+?=M3Pe??QuIKW5Z7_bRMQ-TWAvQ;jJ*m^3ClK z`;eQka$wWq@QpR0IBbA`Z_gJ*-H!8=b!b%xr$Wggs>89R;^3Q@Cwjgj9J)(9ezZE? z7q^}4)HWqL<@RCES9u_~G`@chx9e~8q>zo;A*2$KvYDkQ4 z$o?y8{%9Vn9sV2lUU>@}&6jR}VwObS$_}TsH^3l_HCtmCPEpn()OhMwYIY_!EEpeAak&UztSdydGyn z&rZMq^C{n`7iR95Tn_g^kXJXkGVbq$W=Ok|e-_oH+z(fH3K_IgZ@&fb;ytc*`u z&~v>9uB~5g{WGI`{oK=?^Q$30I^OM*`1MSOym3?Y?>vMW^YZkyZ+FiA{p`In?#<_x zuQyvS%pbb+`|YQTKdxQ>yUN*lep2H4=Dm-97b3I%Or-tW;Ox7&9(4E5)Pd{2##;Y< zYrOPz&ic~N$|HY&TwVSBL1gdmH>;MavI+14Wv$g^iF1icm(_nf+ZmV3u*myz3B8B) zp1$#8YwO#}DV|U?Itb7qKiFHQOXySFYp+)^_`i`r(g^(*u#ABMe{~{feHp0i^)`uL zCC@e<>p&kK_`@9eF(C1KYxp#ygy>b<2l8WWX9l5O2`j0XC80z~ez2&&6Wo(NKXDgP zJ*P(X#wCG}?66A?T-c2=$jLDAi)&j6n7Gt6L>?xt3BU}|wbr!# zDGd9t&nSroLxd%5Bvny~Vx-i-B!z*I36R)1@W~2^ktO)DBV+-}csT;m2e4J;IflWk|B|9@&4V*|L2>a_~t?C;igI0j$@} z`3NdS+FOqAtq@H_g>q&78~NPC)|dc8?bwRxmQ$h$I3NEaTsO!kTsG*7>@ni}5TAISecPC;dFpSx3=Hf`{5ag)l3_a9G;@27_$-8P|b;lz# zM(&2Y(?G2RKL1&x|+S>_q+moogDyBk74crdCd z-V5sqG5pEUT6;fBqMbx*sOojk& z!wp>L_ui0bD7We^moV54h}H(C^BtF61WM(2B?iQRE&I>9-?u{btPi{%R9!!*@XKj? z6%J4FRz(F$pe)_{DirED@)$dGy}(KD@_;Caa-WD3Bg!0P;QJV8JCck)2+8Bi$9j`+ zW6newgN8{lC%!n>fa1qIRvUb{tNifE&Vj8ef#M4x#jn}*bhAdMw?bRFjBBlejV^vl zc#(XFV#kteA}U5R)R74|<0bsIKIbMx2O8u-FFRdsrWPGOeDs?_wS#-jn0vsO>vIR$ zQV?D*b;!rkqu&tsUeojS7-)*G7|oQc7jd&9j`2=P?0Kr#lz3>*7=>OXrN@TV3*F`&zcssU7D zs2g9r1B8+Fkr!&AH=rjAlYIBfo;-ZzdVI) zIC3h0lwYGl_F4swBj3TmV+L5*R}{jLh;z?jg&;+~xAe>0>^9<_-3CYN>F|{-;Ouux z<0`-X%-v1jeGf&SOooCtLPVG^Fp_k+ihD4qBXAOzwf zO5kI<8N@Zdd|z1}p8-(^@Jm-b>?WBkwzx_qx~XUCTL5xu>vQt73^<-*|0ACYpfh_&&N^t@l+h8>GZ=DMWGmrI|x6*b$dk z(%$>E?m2B8vx2+D$Jz@*@O_36H^AKjj9;Z(#0_bFiXq(a8lf{J;>iJpMAZwDGVuo~ zJ_D{)w)~AwP%0a504l>Ts>umtuH4hgX5u~gpjkk%Z|!hO&nG^FI?UN07qfljug529 zPR>!YDiH3XaKWTndz;oN_6@)eoZx+PJCJ~s0T%acxT z;@SHTis{Ez#bmsTfq&R^?JiHl4!GG7@Q$@&8{?qOHn&Vtc8E{*RZAH|M%??eYv zZ>K1K@&>s~Jr#E&dvj#N+`6YX#6vdtxRk8F;7o%Nz%~gEl%usyhkutlTL(Wd!8Y7d zs*>m~SI!=23zJJ9PgIQl86-yvt_%w9kK_(_-5DpW|qDea$RXOg8D}0ghD8?!qKg9+`@fCX^9629O z_>-EQF~lK;^hl;ui8eaHn*<@ss^5#>6C(i!?T=$6d~%&LeIEaqy=M#FxyQXt`5hI~ z$MAc~A&W9~QOvvV67(AeX4r1?>~%FEQ+vLmY?!0<^o;l~K&sGNHDc-_uKX#PjSp^6 z%j`7ER|Ux`5|vc{wXNhN*5AMVM3v1{<1uA&n7ax|=dUp-1IgO)U)1mUKwG9pe7Za{ z!V_~V8<0$@`#WkDxaAzPCEiC3&u+?Mg6rsLrx3Lg?)lvDtV@a-OU zlB+dAx@XPOUhHhm7i(`f0XkdyYLz`UV0-J7E8|+6J%~vWssJB^+3R!2{nNF+?QMdf z$FSRv9~FrUe8V~`HqbF zcjOO7fL-x+SR!ARE47%IK1>8{9!QXdN3MLbaO2~9Az0F7W}gtx{zWYD-p5e3_V;!$ z6XKnOw`<7O!VX=^7b01((Dv(0Z*>i52lweDQkILVXDIVP%P2w3`(Jlt%Ejh?Evyt9 zwh&Iq_Q8&x5OJ9_^dw@Y=!%b(PuOusk3V>ci#r(aMp61rY3n&ADvF-_XV=IcOL;$fxRj&RwvILe0Oro?Oo21n}>^aUGq;?g;^e{;v6{-yXouW zX7ST4H_^4QCp+u6z}ZvJCGqIVsnEf{pxZ3AeNutggMKx`@chJvV;JBKM`ZZ95m_4+Sq+I zFK9Baa&r0iZj}k~F8MmY8&>X>o(Ny%y=Jy9vtd@}12To!Hg9&So!3&?~G$j_ir`HRm5bfp0hdG zIC(C5WW4$2t<5{hlYVF7)ZfMNt(=jp>24f5G%G;r@%%35rL>hIG& z;x4+1y<@-6{eJk&n(`v~S?|tQAZ7_v1f3w0TXs`{ftjPyFo`uF2G_4}e+iE8sW1|+ zr&oMMm#*Us;+BX>>UmtxmiKHQ*rF|C2a7-+@Odfi8@42nQ8dblqgVmWDoG?qgxY6B z9%n8RZxQ+TZ1qpP*jT{&_U5P@sPfqLsU$zW@Jb?Tw`-S)0nr;N#x|mtL{R+wJO-|u zEDt)a$D7X2xmwPTKl*)5;l)#v|3Fuao^Bch_NEj|dqz=%Gc35noizW3B4PdB^4D(U zLapK1p{pt-m5c_=ou{*Y9;kCO__TCPt#eP!SNt=;^^}kJnlAasu9-z1f?e(2D>{k0 zyj$-+y8XK0$J(d6@B7>M6vSLl%VQn6t1L|_iOh2zFtPZcKK>}{dR2oL%I*8{Xlt9B zPL}rG+Z}FmAS-`+bWYPmYReipi;fJbawPD_gOs(&oPjQrNH!mPJEItWo6V>Son`JSflJYWObRx)?j;5V} zvADE~B|a11KqruMtVlIw&RE$?9s9wf7Zrfh z)PHKh-q6D^4zWKmArbykw;+i(B;9Rxm&AL*3QG%|eQqcb4!wP5zV&)z6Qm2jo0|z|}+>*9tX*mAeB3)ba z!Y#b*(a<+rGX;UQ1GTrI0`<8%sEqgL8|8`4`%5B9PQaN0^syz2KJ~%i+GjpO@c_$? z@3)y~>U6fOaGWA|9J7c#X7fa)RmN7vf7BL+kMbF|=iD1uuGcT$(t% z1M`xQ9=4}6-d5bOT5>ottFTf;%$oYu6)1DLpNRC2IW+E~|Ba;AkB-bg+(LH_*6n4b zT*i{72$OJVc#X;sRukGO?crkHfYP=3V>1{^OzA8@9Ipm5)SG-0pvG(%0p}e?^kG6T zyet4h=U!r)p3%kj8`MJ2_`I>aW1w`EiYEH5;^i7YYj>pVz4%=FvH_c;ALromE<}Fj z)mA@RFN`!CN~syTH%L->`l8D{#X?f)8;s4RzBoy?H92?>DlmA6`C>RW{$e@+m@Z1b zX3T*C4E$(3w+*r+o zm?;ISUQYp>Scl|OKK@DAD92<}TQEQ(w2n#9-mueL>AEtQ4o`q`Z;(r3l{yhHG{i=^ z!c29qvO1>izr&U2vnI((%qh`O_AX_;vP4>UW17~QUxJDm(RoN3_<18hFOimvefB&x z&7Z3{(cp2t7GxP3HR*Bb0Z&jkc{Lyy4t=-=H{R^#g*n74x)<^uP$ea;wpb_R>$ltL zrZ5X4oDDOov%;fvjSZKlcyolO%m|2;|2^MW(0EoNZvv00%mc1qDNus?h->!T<;ec`v#A{9yrQ{Wm^PSmu za7lqp)P6g!2vX66uj)Q|yOjT@&V|U$PBifK$e6Ywk`F@FT+LI_Zf_3|l6F7PGRF^& zGj&|`l1^quUz(WuIPXWzr zC;`k9Cee6|drFu}g-!sfymH03Lp%vmD72zw8cQMaxh0MV)y#L8N{L`TDNG`skc|&* zuY8%aB&#iGg&?$Nu%AKu#Ed~~O>tzvVU~U&-0To`mqPSEP-)FXD8_*%w$VX{n6xNLR+lwb-XZ3Bo z*6sK(g3an#2L1M68}R6h3Igs&0Ht`e{`ax;^o8HYz!uzD((mTgvs;S7l)~3U=rx^0 zRg%|(h_jYYyluZ4r7I6|3%St82!D!$5PGRsP_T>B$lvYrr<z$(3!T*!VnbXh|39uM`2&DuBOkKeU`WOTZv4W{5(hR8sCnJY$|`W zdlsEM-4!SM^;%`Dzq#U1vC|W}TgpT0^A16=qa`a%aAmCk6!*c%VWsAp=A{LfxL+?X zx;EcFF8DKH)Fi%B^R)soX(6qBE_0BQ>71I%6xzF zWjW^Unw2UpkBv=*Tmt#O!G7MJ{}$i=M=r%Ysfh(Uo$6~^IB&oRO~L_}H*P3s(ib)o z9HT1Vm0+i7r1MvtQ|K)7W#_CqA5)r#Jjw?7`gXZ7dC-Ffg-yPp=wbtdx}Luo25W#wCDtx;!82dw+04z-U#DD0_g4B;~%Fg zaFPa&Nqq1zp|~Dn3pDB^N+|<9_ue^vNEFWoU%<%32vNRHkedM7Ib1&$039QshX^nX z3o*5Z*CU{%ZLDj{XfRz~==8*9llTyWk_y{sl&yD1Wi0VNR7=^SZ8z9dME(4{J~ z4fbK25My+dW;Upa9k3#DX+8PEx$0!s4W0F)O*vNYtLVm)-Z1HDc z@EJW=tR%XDh^;(}O{Ajc4Mpo&I-@iyA^UVAPV&B*%vmXsNhi=508QvlA%8_&zJkSX zN7eNpU)@WUB%h}gU`bRO=PPUuBU6f#Ji`vi?8_E6k-F5!136vTYn&r_GzW8zmlBhc z;Fg274f*1S7{>sqU-0tbP#3AxYN!%??&z=(HOivwI(kW-7@Z2wCB4Z)$Vn3AfxLz& z?FH0$L#R9hv5hZYSOXa_K(9y5ieR9tGpOs({0ShsKW4w2F0ybAD9qjxoiYS>m&rfT zLoTR*TnQq|WKF0bL+ZJhjvI8ErE|je$X;YVL!Nksm9jkp9)-+jzDd&*APG63DORd- zf9jT+3{oyVQ^i6PnNMBF$?4CQD$3b=DyJYIhsP@__?et$!z&3W%1|pBj?Rk+N81ME zs-;}4kWb?bLq?-C-`XB|7$D~sBa-Z$ zw776mKOA?YOk^x9Z9B<45a%r5!8ytnJB7uSyUOBhilmQjl@%Z5;R4DM=aWU$iy;HS zHy3b@AQ_O8Y!N~U)cRUnp9eQ zp5Nbov{Z=tVR8-@ep#v<@mLRA*ns$G=_=)|AeEzV8+#>x&iZtKPUFk{@{JYIL}V8M z`G{~c3VU6@QLNi!4-ixMtETX^ltpD*IVQDg^mS3tgB*o`qOuxZAu=buFNafDHQ-vD zBxPWJ2a>JIayM;_{NjzO4ui5V zPz(WfL<)FezUP&BWgl`6vO&vZN`+mle*1;`pP4OSnrYd@)vlPdfO1UGYuaC!n35A# zAIE`;Y>Spf--1}993?_3Fs%Zn#B0R-|e#hOj6_DiX_HXBiV>S zR^(Z``d@wsv4yJBc2d`ow~BV%a(Ghz+4R323#n?FTw)u;NGK?$&%**Q_}MJtO{Y~H>d@+~XH z&C$?>A|?l2 z*zvPYLiAWn!-zP;0t(C4RNaG>D`U+U1`^Qt9p2?EMQL zo*YZeN<=<-ofcX45cN#=;$Hz#-dVJf4njGJ27Wir!$5a1k|#ck|K%VY`9LUuR^#q_ z2>W?r*|!^!`>x~J?f)t$kBStx_^>~%Wyf$zVd#yok3>uUGbQZcG-Q9v!-_iW zBMN}IhP|8SV)bDHc*nK=cd+4O?S$Y?)%4EdB>w1^y&rEw=E}r$JH)J>i~LbL24CN+ z#zs77ur}lD!>=Ko^|W@Oq~jV8fJ3)!UAKM52@RCA)(`<4RjiLi7&!|X?LCwYd%I7i_Xd<~M*^lJedrrsk+niOQ#u^v)T8-)Z^(Jr_{h!!!XE58 zOifaRbgMTpxGy=qFM6`ONe1XM#7XlJV*vV$-xF7}V~9?mmX4||6X_IoVI>hdHDbuz zzMH`Vx6%h{>IQBP4cuAU8n}xZY}6dQ?=aXLJlL8(*j_jIaA@$+(%^rnA%W&lm%~s` z@X(X=q5is|!J(n2OGD34PoHZ(9d&p*7X0)Yr8r+c=k?Ij_e)RZ@}Is9?)d01JQF

e#z^Xv0TcH@!7R{^6i{#jNc|qjnE($2;Pz~gY3&K( zo);3!Ln04~#B1xRrHrc)NKH04(MeSEX^?Ej^S(Yfmj7Hy`~|6$#N@-B8^FXh@X<23 zYM8Hf$mrj?VKMcsyM~@)G8>>7zPM&7=wJg(#YBYxoRJ=Z2;M+0a-h{9XJCM#krq)}kw#Hc9707A zq(MqRkPr|BmGH-W^FR2`_nL!u?OFR-_xs$}HA7TbvTv-gaDW}qGpQT^$19K-dPWeT zbT=1dg`Uwy&4IXJwkUd9OPDD-C!hml6b5rY0bitpY{Ou;JD_W$D}z+4azDY=i3 z0Cfk{=VXNi0UWi$98PBLCa=DKMOYgBNY;h|vAUz(L_Uu74{%RI43U9sT-5ruR2cUg zWCi3EanMK)>MH|^@@L$sbzHk#)NN8^x2i#L^Q5|#q$L2z5JmmnDyGwaG43I)V8sm!Dh?$w#6`ov_C4lv6J*l=z7Iv3QfK4Y5;3OE7Nx`V7X*0@_&W$!_K z5CAP6=H3A!3tQwy00wO{7K1aY>t8kRgmZ_%*byLhu6Z&%iGviFE(|>N3ha&mvv94` z768_H+s1iw5YCSzoOHO2grS^)58pTVoCCE^Hub&57i3phr)7xv8AUmrPAZWHCA1I2 zI7e-$Hr>IDmY{Sg!nC2?3JCpmkza?ZWx1cvhVG9P)34dn|VbWFQRhzMXIEl_@kSvyKoD2%%G=6etd`bzZue;%YK z^%UPze^hma;6(@ONM8N>{<`o^Ade-P{u!uqZDTTwPVl}#fECYB+yf+vT4t1vM0k1^ zwV)TXsKxP})nnQjed=5=(>qCWu0>)}0C21=e#s;Gs4?Sg2~++=;#n<{63px(F*k2c zVuS#kI|xwO@Kfd2r`+5i_v&@8N8jBGZn#U#XK~PJ{+K9zz`!x@~#aKB?`VMrAbmnE1z?+4NzDVaD|6aX;=ap)sQgBzfm`UKdSr}*{||7 zh7low068^Sn3~%IyemaTCbi5PLH#)SlG~~vzF2=31s4OZ#1N-4cc&E}eP!Zk5aWib zf1=|qI2ug;tz8vrYI$ZmLDFMR?^%5)JG8b=_08Jiw>uZK8+Ub418^5W1Hyi5nbVVZ zfX%8;`-0CD2v^JPe_nqi`!*Fb%Ebdh!Hyo##-5N-BB;|((A1T*l+{$;s1q0s0ux0b z;fk2l0kGp|T)KvD*&*0i4U*~|auS^!R{4Aahe2z2QMmdbcPQ49i$D~|f zdd~=rm{!&on9OWuMb9d$fs7wsr66W|RY05%vu9@~dR-`mh18jGHRI)u%ITJ};7u|G zT7;8(q;?&GxV42Q<1YPB2xVV#XnYFf6aXwsLGTW&iA9d+Qp;F*eKUwONL#9&*a0c( zVtHRd(yMI-4AIG0*T`sNQl7>Cg*mJ!;BVobZnpcbE&mQ&>h$^a*k$EU@G4xnmpqJg z_09T56cuxNrn^`~lg7DHhCEtIU5JwBP_~0h7rT)qbEfWW{}VuJV0dE)e1GH5_O0v+ zWN-c##Pn@aSyb<^QUXr)_+ezjyZK&g1X~j`W>VQ89Vk^UsG->|g66v>kZoi?q})$s z3YUp%uR|=IhycBIOK1u1QTR{_ZJ`6DcuqMETthpGHfiIN!n>2n@6BXOQcN~Zr!ZDn z0yX?g?ps)d9bTJi7>q+nzeSFqsJMehhg#??Ov9y-&v0Dt;m9y)P=6yHFhqidzNP_m zz<3J>YZ$FQtIf)Zx!UPmq=m-S*{MZtjE-Tk57)9MTb>Axgn?#q8dL-B(5jnG1tW0P zksT&dLg~~yIFL>oD9YB_WMU%szsXGjL??JjYbdhmY26b7?|{_{8jl__uGGkm_hY$X zlicqZp^zz^%E*uVJLIaT+Xo}ia?4bTcDgtarTj5nwqCl_7?@Jb6`_smnOj0r$amn~ z$2e$*xya?`s#7G>wf(enf&vePJKrDzDD_3=3Z^j%?Gtvm;5WDp7fcbC5Z#ts=IVVNzZLd|f6=zkMB&1_*v77xR|`^&zi$F|cdyW3aYvE!u%Jf1Ss-Xd zO37Kc>e5~_uGTa@~|c)oMU`oo6RITHCJxRotL^|4GyOL zH3ARb?Ykokdaj6F3GVy;@+xHD)U|a7hyvc_5&&JxH1<$i3?{|m@qPW`r$TY{Y{9M| zbMiNCy{Z0YtZ;9(V85T-00T@Cd4Q_Cug~20+b%hJ;a2Q_(Mw)s$uY};-T%d`MlL4D zt|$KeFLoo9`A*zcw&Hc%c9H#^_-_wlujBXX%I+i_G~}(%G#2-Q+(jv4rIFuVqyUV0c{n^~LGp-MiOUf}DiBB^qw<85}V1#Dgoa=xZ-` z2*)`JJ_*CH4Sj(sdJg5g7o<=?Ghw{vT8MN@EM^@Z@tHF4)fmk?k4+d9IKS-*5p=&(@PXc1)M|+X+sN!IQByPEU+e zGE*;!oB8S32uloYmS7Y&74y<4GKDrrh0lv=?Ob2!?Q}G3u7>L2-l!Z;L2gXF7i%Dk zj?86vcHm(Rk}BR%S3t%h*_N04r_x)g4+WV?a$lhjh+-<(vx2N`Z$b47qt>8%_xy@I z_5Z+)get7_qqjZz$j%Kc-&&VGujeBp<$`WVZQ*)=7XEGy0$hX4kKKqfZf2in|IQsG8F%jQ%Cq2s#u?(AFo!} z(=%}KQuZ{va$Gr_Nu$_TwBS)n2Ua;ahG!3Uf^HA(B1YChRu=O(U-d+%xyOIvy9#vm z)wuEm3lw-C-wX~8PP|1}{btwQzZ3kwICJBF#&iCV@Z3b_Z2|k$ZqGr+jXD?x=m}9kQKkDEf}v`SZweD%Jcx-Qf_8uHZ7KF$)S- zLb;(Ob1^+=`-_DUIU)W%?j5s0)Dv|x5g|UOxy!PTp9N@F=#c+!AmEVx$Y{R_>Rkiw7s2_pMi`Uz8o zp``yhDG|SW#*>eAO%k~{!bx62&>3-wqojRJ-6P5~VTGniUlJ{KU(?P&^Z@4#-gkjR zf2R+V&UEGooER<1;b{shF}0}G#&o{NV2X&TRjTxpbfw4Pnbx=z?vRarrl#;b|C282 z$rF9adNktQ%~bY69o#EnAS;mAfvgzrorG|uxfYDD-a?IiBhmtBSUC2_J4WO>AgN)t z#_=Moy05h)A_{lcn)<(G48^Zeh4de?-TI3U0|TH|n`&^orJic~#NhOM{ZQlS$gdwr3t!^)sHU*a10yIyUmqJH^S7g=RnxfeE_YMjs`JQA|@yR z{kXIMKVlC~M;%GVV~RIBhtuF+;~mp6)o6dI|Ka}L>fl@rHL0Ybo&>JObS2U%544G& zh_Fxw4Z1?59M*Ub9C2Q09hO$j$~LFN#)D>K8AAvcKyiM$G$(-Y6bu&!W?{fAB(gpm z*QGUlNFzjK{ONcg_46%L-ZC zTTk-FO62}@S{UkGQ=q12kYNTAt$&5N5r^g*pwitFD7=>v09VU69OG&+Tx|qG0iDAA zG=?+7VpF3MXQR>}qq3y;$%QiIl|~hOtoK`tDnGtgC-fRUJT$6G%H$y85C%G{#Ek2b zBngFGj?FLYf{dTozA*YO#TxnINy~@2mM)~M%;PTOwmBnTFrVhLt~TWOlWiG|2gZ;1 zOkPA8HkeAGZgsxM83&s_mk)fdINMggDr;zB(tBv4Ei31GORgYC)&U|Ny=C&+^rHyH z3#e|FwThwQ}2H-3d&!qa*t?a5}Au+Mu@&K%86v-m%2n~ZlZ#2_R9i??mT=q zMNUuNRCiW?HzNbtXSvLkD6lyi_i2D5M`_5*DpgFx5kp z%@!5+D1YoZpwyVE=eTpK2xc(<@sT5iUh%8$B$n_USDM&c9@#YX^ewR07qHa(=&HAx zy{}fauU-e&5ZD)!qY~GmQs3LxvZ9h6W`PH(cJiv4gzIL=SHB0KX)V?dr zZFVckR~&`y|oxvdC>N9X+_W0*BY1vi6Kw+wgAvF&X9+BuGyl#; zM`Ivv%~5ugWKet+t*=bR{qoo8^q_nQ48>oAY59N!@h6{JbarCX*vs+(iw zkThxtrIxAIz27_9KC5efHrh_1SHq=O!_5|M_6BfxL+SU%-c-}E{teKf$Ai}^W9`p8 zdLswb$4)_FZQj*prbgm*vj|jZ_czvejvU1fbX>1=e53UJiuD7!deb*xLI0M558ndk zZ^Mx9Qq|r?Iluca$)JgTF}}sXYsesZ+u$zL5Q8Od)4)>2-eE_nZ@Z5pMwh*}cwz?2<;!Imj>B;e9IhBj)1g@?f^3UX=6&DEw;Be_J&xD7x5rYCpL z%Jp0OKvnxOEfZBF*tGh@s3%{QB~_^h8W!eKh;W(7&4lieFs!C%pQLjXP{~cPX<}TS z8KZ|hK-Rr$`vdE11d`fyk`I3_JF-&NsEWy3-CgJRFp+-mMjqs9PpmJcsfBOYpg>=8 z8^8QauBr}t_OGv_aZcLUxM3iw10nkux&b5Ggi}dnaPDCvO)E^MU}5OAw+XLMJ+RQQ zG#WTCoeMDsG6KV#ikCpE6F65~k5~8r_4NiqW1xmM!v`~9uEY?o1on_ZKs-P}anPK- zG~_e6$Wycd~wX?1@?J9>u|KWLpo<8Acx2}NJh>_ zLpnF0hdZw+wQwnoAkRFAL+MVcI0^j}pxX#5b4a(|02uaCJ3F@`&(Ti|wd~s<4uk31 zZ?S>rV5TrgD1ZeJX{76*a0F?Y)Yp34ZoI^{90RHP7@E@or|OGSyPgZgr6w_DXiwz^ z2w(%>G6cu?geZIqrQQvf*o`#bjefMfy)R4qz1C*f`{~?sl0n(h(hq7y@{WW;a4jD0 zLe#ssdrj;4l?_ebbV-k=LO(%(re6&J?l56>GV(o$?;c|i#kX?C46M*WT`4G9^*fRLj{HiNGk0EdY3!3lpg}j=d1=a zzOJhIXiT42OClhH)M`8dF<^8iYAoS*F`S59-g@i;&#&!9utwbi!@RZNK>eNAwM?OjiuKg7bbFzh;)r|kC@UFB`H!NGu%%FsGD*?x>Cw{E;c966Ao zfj;q4V2W4@JAjKZDUmj`;e{2my2;TlL|SPFx%;~bHERC^eewOQYIf z#^uLi>RcI}TB%_utT_r70LOOSiBVsKpK}OKq=%`0a|2C>m>T}^35}7v@x$R0;Q!=L zPRAdkMIH-@xbi`M?WTQ;zwPFs=Pp^{UVYGOmQ>y)aQmYjn^;Cc#ksn;=#X)w$4;PG23L{xf!qkX1fP>)$;F`OcLEXhRKVq;zTEJ4ugIFgdloaZN zeY_G2{bY$P0O?9$;CqnJMl>`m%?E)Y-%BMQbZImIsY_*yQ(V?aUe;M8Jh**1l6cuz zb=ma#vgOMqMv{}Utm_q2?%&Lr>R0d78}8nhV26$L!2=TYu*|K;BR$b+qUQ%tt2Apv zQJu!jLIW~59P2}51p~VkXtWVmr3nk9A~t#H2N|5@YeZwZLC00qJ2*WeJ*+y7HN@Q< zcXM+$eaQev*#mvynO@zPEJKip33~08E(DE;Q|ZtgKsCZ5%3(_s=pm~ITrANsu~#Q} z=>PDkI8EB>w6I1Pdd~}I2axZs9`Yzom=UWB*tELeH6GxQN;U=O$4$kGA?b8-AHy=) zm3`yDD7dXzrEEHj+i;F>q`*XlLg?1Vr;&o69%LeDlAFWnG`!|5anfF+#)m(%#XdhO1m#M4O}4~GP7dX$Gq=uB2>4At_R11)`78H* zq0Mb1PrRR-;r&Z~9YU{EqT-MBRue%OXK`webW^gIK#22?fbGdDoqP%PQ#tL3B=4wQ{QBng>Dem_H;v?LzE9c*o5-BgKR>>HYQL*VxV}D(<#p7&(*0wh zQ5em8Bbo59o5Pe^hNT8eZ|zW%#tg%wgCR_D)!yU_8Qigqhtm*K^+PKRPW0JQZMNia z&r@1)LbErb?IECzG?(M>Gx1IxzZApt}cjA#M4tpU8u0O z_*TT{hB7x}e-2Hg>mn6aQhg{l-@ueVOM+9XLl4HF28KY&5MACtNDl}@y@>#Q^XH@X zOz&hgX}@Bvg)*Xg%pEx;~aUO`aaB#O@>WP&Ciyb znuCSI*P=_Nw_(y7#5O6-Zhh80`m)1kIm%TF1{luHvn{jYb{_pL9-It&YuBvx)dBEe zEP+?^frBqS<@{*PQyR&8R%Wi|l+C*`xW-148}oE_7$ifKBIecKtq1LcSHD(%yi&bj z@4!Roouys_?3EqE6tb%)LnqqEaL=U=eVJxFYE}iZx1iPJ;*3)0bZT7j41#-qhIB|- z1$v?-KW_Z7VMLbDOh2Lc^5l*|_%Z>>5onZ9Bz4!ck+ttBf)hE^6!7ma?7fW?7?i}nlOQ<>R zetLc9a_jWVYeL!&^RV&AD&YR2a)S&Vo?*eOHaAFG z-wka{5X@74uee^F?4oERPVT^w?tf+WhM9*EuCMxCA=A49t4E<}6ssQB4rL>x3!l<8 z#HtZqextlR(qW>|8W1a7lYUteJMn<)Dop4#e=Q=LuBDc~Z0{9cigb==PQmXAhqtmZ zl8GwYJb#)Dv~SpT;slBxv1cg0Ro#-#UnkqTe%Uy9RWm8-dEpG702{V(@#8L^*KxA% zj~Otf3!7uIY`Og3n|RK|<@ZwioRz+}NRcT{Y|d@rDPp&(l__araEdmLmpel0SyX0@ z$S1t`aBEAZEW#+?dtvs`UtIx>PAH=rrAJ1EXN@nC5I8)@l zfKc&(AgikFxg;<+ALp+wpz1dq#+!1&a!`_{4Sjh&ElG!h)LP1W+LB|Poj_0x+iv+= z888uiryEtv*uYHd#6!ugRjp^svs*Lybn?Mgl(uZsy_Y;XMRKiA%|f$gD-WWcsEOk& z?tte^Qix%JEt9ZBd@(qWfFc4_$&?>(>ny>hknSG6<3$J_6PTv%qd^EYy!Z{THH zjBposVYOZ%SgQc#r@*^jpLQEkEzDAYVPCl)43uIPN-+>B8|6@7CeXUrH*VzdL}1dc z$(Q&Y#kVr0lP{hzvW84Uz1Y5%ze5Sg6y9&?74f=1UR$5x^=GRbflG@fbgpcASu63K z)!^kQhXC?bdEiw6mQ;<4B-nI^jIUH%S;Mlb*ZT7Z2L;h=cAhV+Bg&Is>XxF#UUofJ z7Z0#$UY`FS>UEzi$dmUL;A!eGgQFmsJNLpBFkWuu99j<@u0AiXzf68+Ry<+#K=SjquVw=iN0D_` za{UiDi4yBqG~bSsw;xn9?~DK75b0m1uH5>rA!H!mrn*K{76wg@5p)H%ZYBO%_zV6% zrk;8_orGBYJItQ|syWvXA>-jS_GzP?%@Ks3*XZ)p5{%K!d} z?#}%;ZW^a9FW#?2J-e8x(s*j<_`$|n^J;n5TGZt}#|}Za^g&I7S$F95=~ryoy`K$< z8_y>OS?KS72*S~qUzB=R?B3rn&?MwCJI5x#H4*k!xGLwUS;aRcZfKkMoY~AJdxDnx z&kmbN})FLwlicz%1THM9j(#1Mv5Z#9r#*Vgtd$B$V zU=Yvn4m)R9QvB42LGO*bN$-$JrnaevE|)u4z&2H?8ZBg+D(n66X)jn&DOGWY%ZPE5 z7dnT^9pkh$QvPWNP4W17$dGu(p!u)30t!5Uq95QhE2lCE4>vLwh32cE5_lLf{7G9pro9q)*)zuDM{ENL|*sCp|(zv)?!zV|Ik7Vk(iP!=!ih|BHd%6`Ve%VugHy;9OzUD_j-bqySAbNHp+@wE6yOf7;{l&q{LT*gPw|!EcALoR3KlDLW}0 z#|KQcdF~fVJ8F=_if=l=OdU&H97}^8%aR?-a~Sg}z%8SA7} zz*Z~FRu}FY^TDBo!%UHns&k+7v;S^f;cZ}#tv!?fS(@N+$?e1l-vog)j-L+`X9VqC z*Iu!@POk03-`@hy@80$OGOD%yt~Zak=gc}Gh!*jijd$+Xx_7a?vdaHx+H5_=Y42du z*%Z&QF1^0*Z}rN>4@d1bC%-!P`_Vqf>PB)U?wQ|7!`l1z(;uQa7SmR#T5o4>?Y)g( z#~8a#hg%&yfh^X8yk4f9P9v`4e&lqSu5M zS#9w67Pz@JvRO2Oc~7v)N<$udHy){o#Fg_ZkhrT*>s7zh`!@}}p04`ur(Vr5R)kBt zRwBSdZo{N}wyw4*%CuTO8b<;ak!E$5{xAyWOn-7PT9eh}@v)dW%d6?~AS9m%;QE zRL~HtFLXep3BJ(wP}=ixy*DI>9ziHzIc#<02f(Cqqx51rN@5VUDAPt5ihp#t#0acl z3*j{-fgr$-S%>=$0^Dmn+piA@Z-(_nKah(p^RP8>v(wG9bCw|gkZ~x?+uW<=v?~ev zU1Jws!XC%SyUfUa?4{Glc&nGu;1P?9{FckkyzB20iQ48qiKcNdkApgx#1eQsSLzUt zlFuO@jF{)hfl(Gi9>)Rs+yOTbkXOapVwM1;Si5n3NPZ81Bn>I&9E^$#KXnj$J1ick zdr&`x71OX2A08DS4v?6HN{ZYD!kDD2>!o;nGTsLm@OW8Ce3eq*3wapWr!d+_9^&`L zPN#91FRV`X-%U_lDqIch`wH4vnw|ggT@MsZZ422bHQR1G8r2v#d>eci@z$uXuwr;r zg{MpvOrds=sitkOzV1aRB7@Z*@x{h3YQyT|9y)2!@oS6JC(3VI!|+qjBs5)@IFRi- zY)^Dx0P#5W4~FIT&?0JJQ&R@zeOU$0M#HxzW0KS+OSFq))ps8OB85th+m?(=}EFvI&k}GTA(1apl6=| zGzqLwy&%I7{8J`V!my^qCtN^5#=z)(X_i+5#k8!}4eyNp~KS;$g|V zATjy~Ih(QgVX7o1y`q=Mmz_`KA|rn~JWohD?cBFeEQ+K&+Rgg*#B>9hbB*kepHlJi zR~~=9Beb8s?8gz!new($<5Q$&{-?o<+l6_NA4r~}Z2Yt&*FRpIY73eZ0l&j9ERR5i zs3-Rbhpa9dUxai5&(?^$3^uDjj$D}IqcE;=Tft{Wyp!1E0 z`k~*!Z=tW7U0Q^_so!S{^HG+f)ZZ|!^Fy+F5aE%ubyJFHn`X1(OIp*rR)_pFhS{q( zRio_!f7?Yy+b90EPmOk%#g+?HIXw8yTeI)IbnN(Cp00O48t;E=T%L0JY0J`nb2{8? z6(s#J+U-;BqhC+2sBBz6jk?;K*IoWrGdNHs+ql}7ce5~mS~|NT@Q1Qp})rY2k((GjQXn}<*rWZIEYSC@KRndkmJdD9mJRSK>}q4E0=gtx#hm|GQ{Nh z+tSQmpT)%^vYu?zHV$AtM9W2rLv*T-B|J-;lqJM_v_g}HfvmwH*@}@1`=-%yK_z7mh zJ0-e0#VbXqN6Hi_rL`K7&NBQ@i}JsaIOW|R=~$mUA5+I)EHs32C-To9dK&I=%yPty z^x{Tpw>mk$12>p|I{W@)o-#oSo#%S>rY&`NZ*-VS<<90jo|B5Gsu8Fb$MJRh65g+3 zM00fI%cV%9wB`9^1?*&Ee5IF6QzZ~FrKi1E78#zu@zojB@_(1*Z+BJm_H`x69<@5x zs$Om))@n2_>mN+Oj8q!D5KbB}zIs`5N3p|R+)NjKqX-K9-_Leukv=Kjm( zk%X4<%a+-M)|Jav11?8WggGYaN@Lpl(YwRJ6RI`RxSp4K0vpYWd&50v)eWyy8H_ywIKHdDNg=$H8D&t= z-hs7d>>Q3TYV7G<)ce zDqH=LwSp-;Vclw$;5NlKTJn`gOa+kfL+or7RR|#Ot6T7mFZ$-GD_sBmOTrMYHzH{;s!NwoTWZpUsYX2THicR^%1ZTqM`ct?6 z<0=Qfi27xW8+Ul=;t1_VBpn!9sVqr|q}#I8;FT>=WlAHt66@eoqD^rAM@)D!$r$jd zIU4&AzdVYuyxp+;A07D(J_Vip_h^3Ji*}cvBc-*xn3d~X)J-H_W_X+Xz5|rU&l)&y zC2^SQBpYhoaJ6?~d)*Owk;^YrE-6#>@LLrvsydA-kjd#i08K^Bc1{1H1=2)<=lQJQ z8^pvADAXl^b7?awhBooposR~y3DJPY!untGqn|4=9Vwj(m}b2}^@+h8?4J0VKU9tX zb9O=RXIZ0@$t0h^;BVbva$h0(k|DtMsm)Wn7YU4kcCEL1V}4&U2HEqk9sc}!yZu2S zg((?g?6X3Ub8qDS!iz-aP}f(97k_?VF^9PiMUzs(Prkl`jF=HN7lPDSBD~)h3ERI+ zVvY2jc%U5nt(T=~y$_U|=E((&Qu`!dD5oXH8lzklwIC2-zJ zx;Wim?7n;B?w$XxF8=-{+`t1Q$O1f=N{vWXWOObVf^j4vhT;5`1;cgJa1be1A)Xrx z75Rr4Md%@=1t|*w@EeArf@*-yC5iSe%hd?i8#bFt)LUfq>b-X-bRD#Y0&0i%#&~ko zeswci*VnQpRf_SFGuZplz87g7pc|jS8cLV@TB>ulBJu>4A6g4`^^wApE?E8}9Q-m(iu`1HIKD-5bSWT`QaxMe9Db z8p~SothrH=$9vyD@iLRl-#(HNn*p1TkvI7}{RX~!nguL83HZ&h=p5Z(4Ccag;jO!o z^h}MnveV|50AmWXrO!Byrrysn4@;K=s#Jy+8FUa?Q|}7R76f}r#hIM_^dkR!u6}#7 zR3UIJnR&gcvsEda`R_w!<%DgZxa2O zr8x1yI136H1{-jszpCvfnwHbi{hrC6znjIMsLD6)#cC6}cS`tO9k%Z;zG2y|Y!~|o zA|>bju#?PBG}70WMJs#P({fh$rKCOX-E7PkxOBgto44d&Gd_R+ds}B^g=ZEAb^lIn zM#<+}sl-pje#3inm7T11rj_l?SA*=Ka*pQxhmSq-?Dn5G`(Et7&YWlqc~1I-EhO#q z4l;u8uf{*e{^rNG!n%a3F28)7C}j^w4;@U1{GfTG;%Mxqo6Fm1_ST&wL^|%l zM^7FHlB%rDCW6(HMrWgMHBR^6y>WfsyzF#+dGxxf^ViQWget=Ie}o&v&7lo|%mD@A zL}18lH^8h)l@vaHIvfETP+>=oNMF(wJbr?^OU{6} z6VX^X3g)+%+hY3qRfr2k4lgveYDg-4Dq4%Z6Ki#Y`Sa4-0W^7fEe~UsDPu9JF$=kF z$wzYw4-hjB;Ya|MY=d{s~U&4!=3k2Q4I>?Vdt4%h%; zF}`fjQlM9&CtOubkG!Gry_+nT!>~pJjoeQ_35)^r6l;^}{sfc<3yLI*M~E+5ny$=> zGYi#5)45cj4fppVYbh{o`;@3#>Q+{X5DCq*7h`S^_TnL?QUPy#y0x)ZwrJL3@6WX9 zn}0!>`*vl5BWWP=v7eyq!)S_ec!o#-1;oYKi!}reh>Z>91_+fSEf6r}6aaD)4PnQ0 zz)ARO46Neth;_s}xkKF*;B1pXhjVxYs9}#F+f>?kAELn^2!30M8?aC!y&)NqH?EEC)ufgodUWrLvf(kN8zmpl< zfWU}+ImDEf5)OgpOGJZiH6HPLuQ2_h<3g$!!Sd!~*_pzzC18kF+onkdrAiX?Y z506CO+D%w&AjI7Snrf&ri7|bsT`U@gw{5=TbtAOoyHkQS+P}I++zsCx&}%{$21PTq zZ9LN}{kaB|r&6lzzu^!G%Trjy&K_PilfnyDDwIa35Xw;qxCty2^@qBO3)L)Wm5W#T zO3fsUR@B`HA7fkK5!xG(8vsFa35sizQ^mEd$)v$jXwcG9e799wL}?NCnic}abDl(| z-@<-yO*<6T{$cgezj=1Yzv;@B&z4^*Z6XmTctN~Y4zExkYYZY+`4Jb}|I3;FIAK1A zCCF7N1lDI+Sbvd&D>0w8 z@T|jHyQ^Ci#|QMQXaS)Ox{l4U$s90C4I93OxedK&3_^P55+YJq1lk4q!~wJwOKcu^ zZ1V*e{q<53F-xnl;0X%LeYo}ZArJYZyxTF~_Urx;{O>>FVV}Qug9G~dvhk7WhftOe z{wLE7@PptF?}h(#-e8Z=WoSw$HL9&OcvO2k1Kmu%lSqSgp+Mk_Kq#GHq_tpdp&&6Iyh|sPYAuveD3m=TlusvI zWG!4)DEwRJ>FUu_hi2g?GcHXZTGDewo)}!MyPY2a1dE0hY+nuehChiwAbVAM)FE_?V!PU$y)WXXVf*aNn%#q3p z<4r2xpKFgJjJ^xDQJi0zio_20m+}nwQgn!ck(7i}A%u+}Ly@$_tWx!OQ~meBJKC?$ zDF}cmesT(rFdbs~IK*W-Ec9_$%5)^Ib);i+L_26y0tElW4RJq0wt2AeZIR(X?AV$= zJVC=Ehr==-d6s{@>%q`5o+{VbP+QrkMWzlOj<;M}3I56f{QD~$m4?OB{gJoix%WOtSd~uAMg4=3nqYy>Kp!JSk zCzyA#B5ShkU@~HOec9s6uMgkhXv%BxjXRcdeNDD8Od^9~?zz z>mg^WHH0{JW0F{0jW7_b<;j}kNs`kkBb>=Ex3+HO$_vg4c9?(fkvJceIDFf7n1}u` zXYRN(d9-1Eym$P=ckVJkt^?m9Zd=0!Z{MJ9J6hg4+6p-ym=K3}&}r7*Z03nUWn} zfVnQyy9A^*4Mm4-2*o#DQYHAOCZjsdxj4rBQ zZ?*=2r)95M!WEFTbo|roLWFQyNvr=1hl#>52ii}pC@Th|=^=Akrkg*NsZl5OfX6e4V8a16d(5Bw)335=`HVtpqPG&=qv*NO4!@4`XC&_ zV_ng8+xzx{!qPMc$U3U@iHF2Y&Bsih*vu+FJHNmYml2<2xL~~YGcHY;IJE%3s!|oZ zU;O>T+!Jp&YnTH0b?cv%2GV;6_A>>I*af{S4H{nv`ot7GYZts&8oaU){Dmpxt6fO^ zfiM+q(>JEj{t=Pa?UEPsT+FrC}vHV(*@bVYbA&MP=JP#VMF0`cov1WZHB^ zC7&?7U{MqTY=k|>WdjM>Qe^W&HaiTk;u zd9un6J(M5Fj#t~LhZDCJHxFT~Ey8-1ZN-VHYXr1kw}+xK&FlQ(&XAKOgsOPcN%n;uP? zwo96kbir0^m)03fcWh0+%cVl_j7b)bZD^#^bZq5$=Cr)!JL{;xVav}XR-vK*)BJhC zC-HBmCXy!BH5QkXn_M4lw}QGhp%*sH0=B`PwkGm<#DQzeedUjN@mXB{t!S6_fWIP^ zb{=VVswWT~OZ&8Tdomjm$0?HdV2AE#*xD8>GK@6wgmkeG{7ByE$qT3UXwUHb4zc$^ zlOQKn6fwzlvvOxU2J$gXkByZBEqbYz=LMOj9k=D_1f|=L8R^%w=`ZB1wT|4x?cB|1 z8L48nU<57?=9eBf6g)Y2ibNIMr%jP8rNHtcyJa2-Wd_ICJ^1v}dxzYIm5lSsi1XIV z7y+1XYI-EolO%J2n&}1K&%(E9Rie0>{P)QcjhCwj_j!ZA1uFIhW->SY*{{_~h={Ul zFuQzY*;mhB(V*xQaD%MU`B_ohOCiJfC)sRbcFT=LDzXJmPaiBltzv7cb8320(bT-$ z)XvuY+^M;{qPf4X`1``sBe+8NBWBP{? zqaZ@WFyjVI+n1P#FHI3tKO@>DB7a;8Dk%!9E%H!qB1L!vyMkU__XS&ZQ`we93qJ1> zlZ{CwgvKb_4A6Z>N?Go_41Xq^7>wzr!Y(#DU&`Mr`%+w{@ZhgPjlE*?bHz@2rOq;? z?nQ*|CY>|wy8*3NZ=0FNhFG5&BI}9tc}$d*YT(bmYIi;FUbNg52Bxmd5O5SaJM3c6 zR*T{y<+lyyq6qMdBGsfsIx~QqhN$ZSc9nTDPAVk!6Vi5wdxo;Fa{;S5*JSIkbKII{ zWSecqpyyM5wNR=gR}le4nb4MEXxHq%sMK<3$Q756Vg9HB3RURNn(Js@A-ZjEj} z&uW#kQdcnPFEcz_-(|^CD$>Lgd|j{S^Z9t(?(?G=`9&Si zl-Wl92jhx29~W!x6n{$;dR16rl?S%X3ph3|WsdLWVGKx+M3`nGy8$VqWrD?KSlhBV zZD~I-?`Fx@;U4)_l(TXX##IuTzfwA)4!w>%a{KJ%^Hq(75!%1=3-3hvNvfVbYjWYX zq7~viQ*wUVdtu;C{qUQGNxwI*?!1|Q^JYnUadppcasAHX=9|UO(o0|cmUejRE8>?r zUe`aY9o@TAJNLV8;Wqca_k-%J2SZkR9Mk1rI;_tV@j~MdOpAP>Lpmm(A!!v4pIs8g zozu7eh+N@HzEEE|KhdP)qkHE?B7c##!4K`>xW@k`8#~%{6pD(jWUW|I_#b5pHJiSR zaCz+Yr?&adBMHN*n|*DTbAh4q?Up^5{J`era=?E6tP%tCAQe6zH0sYM(-pd5=+c_$ zp%S2XChXWKgiYW93=d`lFASd=M88c-AU=LYym+W33e3+u)S0^7a=lG6zwOy+O#oRY z$p!Ndn*E%zb5vX&Dn|{M*NXka15EB}|Nh+Mo>T^?T`4@swBg*tzqbHjmLq61?(Jmu z`H@*>$`ON)?NPoRLJvBY+J0gJJKvOc`e2@qM}NVQd7U_p_NSU|=FAnxYzm=aEHf!@ zr~uUID@dnzGybyOUu9yFxsD9u*bUFcW=0`AGson6RCm8}F-Yxi_v1ikYIHnN~KE{qlM+&L=4zkL6GBNVD#nz4GeOcmqkqd*3 z6$4jsl*?F~rplq~D#vPlhnnsU-@>b34yQb-a=49`vE|`5R2wG16N@XToFOBm%>PE+ z(@C_DB(xy@hXMcs3-9)Rc&C}m+2iHmF;UClY z#4cuooTn@5JOny;aW}#N!&!_j{?zFECS#W!e?LYI802?et@x|#w-26m&=DE^n$6mI z;2^s!kW~8VO)V&(c$Gx!(kCx2AeFGB&xj2V32K5~4sbd0{NUZim(QQ??E!EVE)6Og z&Q0aLSLH3GgLm?x$lMSzCm$~On(7pb$93y6FxxQaILxZ6_O;~PE?2j}#4BiMijxBl zT0^#jp-Q{TWqX}y`~9bf^%z*e%!P|OJ?dT~L=0kDAwtn0V3 zxxx|)P)&!HRK=RYH$zc&kn?Q5|Xv6GEOtfg!R^y;j-B!~Gp=}NZ(!i0eJu=)h$*)#; zBA+azy)J$_o5uI%v`EP2*0YVOx=*cJPc~yy4~S;HYTKQO`rPqzt?qN@*6rcX&jEzS zeq*y(^mbwwQn`M+8)dk)-Gi~x*y$Dah~DWF53Aql$DZEW8Ng*~d>K@@75!yMrMmvh z3yr5+Uxx7m8ed2BUqyc%C9ceqkVNyoDq^${8 zkC<=Mf6`b1QrLix-(Ce|e)J*%fb1_Qj28d_8X=%Vzz1+87(ng;5G2-`RoX>I2<}%s ze!1)aN7Z*R@F!%bHjk=Ci--vy7KR>Gzbqlq@7}P{ui{i#Usv;c(R_ch+NlDaKF5Xe zh$zHjMr`H!vS9FRTWPx|^>dHHCu{xwTnls)6l)`d4?cPDrY-sFhc|UkmU&ySHtp8z z+=t6OOd)mu5%J}2jJMe$GLXjV?*BhUKb#>XcU3{4oV7k#bF9vPG`S4SR<;rL9Bh5^ zalR#i&##4~|3XSA^!SWJd&|!1p!(q|o4LR*>zoQZt2^6|9R#bYqn5@x{>-I!#DVv; zbJ=abzHUr@wJ!j^J8bn#50@N$e!((BHMt6TXtHy^>L+eFArIeN^Q9q`YH;yf&|?~S zM^j}vT{u38bdHpV=}Hwz+E~s!qj)OKNf`rQxujBMJpUxDi!BH2;VoaUNltAuXZ@}|g6`CTOJi0?#=QQhH5`<#Rx^%O&9A`VvJ$&+aC7*QRpqn%7@Y37g zqg^M@-dJM6Gt%lG4OThd?KBiA0+0!~O|2&aBUEH_OrtG_jPV?2YIH*7vlK&v@r|~> z9B*nPPbGKT;oIwV2T|HTHuX*v<=>!MDPZuwTX2M0Xl z1E~xLR%DDTP7a!Tb?CJ6jykunvOlXo63H;6XDicD6V~{lFL9q&5=y*IzTw45zXoPOkwkKxkXAeW#||6!Iv3*-oLy3_>;=SV4wvtRg)9uQvfM4TT?tv;X+ z(arGrVg}|>$t6KgDcF5y4?^J+$j|RLfrx-51X`@*Ya%`^pYq1F+o>gh z11L%6!rFdv9yKk0&ahEs|0|dPDLE_9Zd`+H>Wa1ghT*^w+vfN^*BPc~&~aG-KjnliXe%MO4Qz(JtgvC5g-SOjH7z_fu^r?4 z+uaJ$or3cMn~{M~4pZw(IWy>OuCPa5lTWf7zeMRg;xCIg_$N6`v2;<5SNYiltQ1)f zv4njWe~2UnpzF9WUH2{opGohDIsiUqVulc4Z{JkUD?1kHDS$S|$yk8L*8?Mg z$vs`cdg-SDK9fn_1ZwC8mI&kQV6Fs;y9>|+_6Wh8W!?LE=u7@(%hWfakZ5EqatTrKJ--=yC)YO)IE)S051ijqZrEKUs7+sh@v=+gzBNC zXy4_AQ46d7081=;2@XVn*xI|$w4o1L(BeU4&u}=<8j3349}p}OKwJY@a|X@gYs|#k za<$%!UAHL>U(jexaxyHk5OLCpZhdP*LohOMfG2O^b&hVNsjvE0f=(x;ZO;SEu*ZxzBnH`r;< z;+|a@=#cDt+j?2r?levUMUoHo!ORWCjP9plr7B3$F7hgXR$~}Pd9KmmSzO&G8Bu0( zG}8}i+VYNpVJ|QBk7j#+qXhHqNX~SQN7QQq@Zd*z=6+-{8GlZySxh;_{ z)=B8qz3eA1G+k&ICm)5Gf7S?<)xhbbbBo7P+4GA^BZb&ji4Wh`E*@9IJT<$WeDoOZ zNRio0q4iZ<-HA72MLHRP_^%;3tj1%5+ERQuJ_9nJ$l^vv(z zqq!{u1-PjFQ80vHs*&e~B!#WEFMQ;*?vqdt&`)>`aRM~wS^3i8L<(7nS-)vJy#D_1 z%{{&}(5Rd%N%pE}#aiYGA2IW%!(gvF5UaKQ1GfF)CstUl^QiH-g!z_dXvorOplRLv zbi8N!&BON?C%Xktw;Ezp;D$_Pj20eI#tEqX?lp{v(dMQ|g3eE5s%Xb6z5toLB4gO{ zd;-B|N4Xc~%%s!_XYgj8Rv8ywKgMjXV;UG5oJ3%uGGZ{^v8oGGcg)695A&hd@xMT? zTDTCfK^+B9ml(#eVi}jdtAP6Wpf{!6V4>dy!w~|9w@+gv*ddxNsl$dKnF4_}LBI`= zr}U@>1Zoj`W$P=_P@n)Zl8o9(5IZG1C=6)*)S7dR{I*KO2O6;PAvg6+|Jy4wu+>+M z@8c^n*L?40_0TQEVHWf7v}QlSrCJxEYax!|@?}h(nT-dM9%t@!`E^k*@PZrg)9SEeOkE;hI*#AA&Vil!{6qTtu3eYI*DTLj&YZF*$-=f%90Hcq91Y>hZcoApAW`!ajQwCvb86JFvP(HEL-&d} zX2>z;1VBMJqvofY1n!WAe)O(la4h6X*R6O+S4iDj)_&9Gq*AuXj%FWHYwGF2b5+@! z!I-t#PzVUrbb<%-$}KdP242oYbb0aEK(>g-wNDtlxE2M%q&(fTz?3LstQGiz4MZ%s zJaW&hVkePU5~k!W;lSX>FbJq=!mIau+cYL1u7+sF_ zi}-7#SyWeUmg|t#U-6U+6pRSl>yvz*dKkdZl?NrLuaM76`WP?RW@9!i1fk zbyAgSciL?=30Z6a6M}#rdq9tHJp!`yQh=MMr5+I9wl7tuyW49BSQD^NbSTc5Lpj4>*O&!th7=m)aF)# zI{;;Yljnr+P2jWc0(m0Z&u^LST#Hwvp59sEImo_#QYi08aQqH9|KBAI_6dW`0EfUy zB*xJByP=Lmu799BpMC%a^^I_1QtybEcG_g=OWhO;M(Rs4@69uJ)oh*VtPGwmf+(*& zy71&E7csEz8)*Y+l^{F?u590rpA*d{f#e|p0Ln>VVW}v0W8GuGCE-xqGaa3Ntkln=Sk*Epu%!hr+JAzp`>SzZb|l4Riiq2z?WV zSMvlWU6kaYf1j!Hnye0nFM0lsJ=Xbq;Gr(KQ==T;f6~uD9F#!b)3*HzQCtfaG$doMc!nnTj znK7LU-kogNQp1S+s#O@5$4UTpybU4&WrN(~A9)+j&7@4<7BmHm)wn(U-kJbweK>d7 zyF=iC+PJ(S2l#b~CD`_GDe~4o-iO*?c?Cf9opGbgpZXfbhR>H9#q$(Ysov6m8r2R} z$_{JVkeh^dn%>@SQulczxHs1{WqdxRP(g?aEJZ#d@il>PCH(j%V>?E6@c#!M4$H7u8K6W!?{&D1H*6}|LP!hn4 z0ed+=aVrALVnB~}9@*KlqUN8bJbg;pd@@G>sgl4avg#Q{;Ap|e5yMX}{Ap1~w1lgd zd@;sbQfx3wK=7qn^Z=4&0aYk$$!J~H1v_NSdA)iH6XW6Gz4w5c{* z)bYBlV`0AIf6~dGROiZ}&bL0DYv(#QiaI~Eb#Bdfe%dEZq@I5{^nBOn`S)|re-=Ie z-S+(N{PTZ*o&)=-h9+#NFB_i1Mi#Sq+u5iEHu^6cgY6PD=@Rzs5>4q6FYc0T@4_y0 z$^7lYVY}r_x)pr8l~TG@7V2i&x-}NMwf=VFu|2vbJ!6{ynkGs}!4TSe4C}>AihDwL zdQ3G0OtOV6?0fn^y|QJ!kj5TS*xjxWZrzAqg$cp5cy6D43_G8DW2*_6_EtGFL-)}N9x5Q*w7PU*dq zJycRG;HuGA+5RFcMbgQnH$HoiZZe!P(%VuzSnfLBQZt0{fmSb))#g1;7yvUCpsPi37YVX~LgXc#^3-bn+>R&kfg5%W&Pizf!V>x-g zBbCL2h#Zg*&@YYwOXh(1Nuzx!9F+7(PyNUac4BF3ti5;wDhtx%Oo(#EW$uhZat8kF zVP9Mxnb6{&6a;}aJ2*aA&VjB;J?AKP({X1T~Zt(B?p0G^fd>lY$tq zVCkf?=>)-{KQea&!~z8X@MsL+oij|pf}Mf?iNDppeeKxM)h$4q1oOqfr0}m48iw9t z(6^1p+I^At@i4tN(_f-t``CI9o<}~nUl50A!}E7IA+;Sa=X0h6yO7HP=!2kHf(fKJ z05y!~eO5D9>^C(yK0q_YWUvsICZMhuz>@V zvCcK*L4$9;5kk{eV6vcT7OF}CV;-|~zl^Vq&A-gz>tOL6)WQUE_;5Jh*G~KoG(p+; z{nf_bK!T8>--6gk;|_QS4h3SP+E{$&*-IjgU{@Lp#D=+I7A~299B}Xu4pfMQQ6|B} zbD=>1oER`eror}Ag=AB%G8-0xfr;&za*0j@XdH+Pz{6;;H))_~r)lsGI6C(gh%<9_ zY~A=HAccXYUU|izJL8JkAm>hl@N%-iqyveoj)7%d*x+bl)Pap4%#5hO(&q)99uj1o zG@IS|2Hu4PaVNX+{FLamE72>0WiXvjTcit;p%_Gm6aRE9-1IP}jmmqTg}8?S#4$^O zEO;9Rjl&F0kD(g4y?O!gb5!(Yr;irwEw^?Mh&yA{4pOJRC$qrnw9hO4a4!~EnaUM( z!nksv+BAqgW`92nBT~VqFTicIF#900IvW$EP#hHJBW zWJwDUS-8y}^-DBf4s3>V4cI2*py0UuyH%+2HaLj1j4oZckzC{Fh6Id;Kx5(EXxLXpLCT=qCXt6|IPWGxHMNj!r+egs^`AHT>=yT^wslZkGi%>Wb8~33yL3wd6oX+&)w!{ z&m7wNDy9jwdEQgd36kdjUF!c8JibmS=0Z&QAB+xLV7B&g&KIA!6Iz%k5*p^r-?0bu zD^k()((h3x1?G-pZtp+$*mB%e$x|0Gi#c;(S&%n?%w{83oR|xXyuc}R@^l{{5CAC> z0ik4y*=xOK^pM;3v-m);xGX=aGvHBbSr=T{AK6uA$uz@80nVK^yDBx>(m~Cn_m6JYrj5%~y+|V;vzN~9TPs4-APm5oj z1uT5;MZ&HW)*Y)w>GF!58hs{#I%bTsOA_!2TAOX<72>{r0G!@|Q{x^u1y-GrJ|c5Y z>`PZi_3wZD8XvH${nt$|!lk`;!zb=Jlvv*J{uVjY;P?D6@v``w(fS@fx|ciRqh?>w ztJ9QB^{8vS^q7e@qegdUAf#A<6_%~LN?kgUAdHA13bT|0dd=Wn?5vWcTtvh%~9?Wf05;fOYI6o!EzK~%o==%(H&lobheb} zD+sWYy<<#V1s}2~P|Y{5M#>%^GsC&CnP!v5V^y z)i#M0ocDgsw3^KiZn9A>N!PVit*+Ds<_15kV)+O`=|zH1u9afB;*t+q60Y#Yl%^4a zVk^qNw0^S0ju9i&x1l2+a5`$nHK;%6%V54H!QWr&FdKh__MQWRywr+Ra?5z>LjqEb zruYQ~OaksfHL3jRPA7Q&*%Flp8jDqTN_%?+l#8h&0{!OWl6ZP?j=AhWnl(&bL)*pS zTlRpz+~kg)cT7lluj&`UC$?cF83gZ$>U&8x_Qhom!#S3hrb|`FB#seR2;gO`UhXlp z;a%}^vJ>%9Ya@?Fn%$Lq*UOFM1wW9%Y!5US80*kc$W=ax))PZYU2SS%Flkc=$ z`Kj^B!OLm9j0>YtlBA!*P3d%A9Yi|MyB7XtgIrUU?1Z;CJAs4`a#^c%RL`?nSBA7* z?~Nlqg}(9TbKgqu)L9ru+`ARp8ZjMt{RI3r{|lEr4+gL7059KVs-=AvNu>)Gm?Y7a zQ3BzF-jWN&OEmF2s@O1va3R(xH91?OX9`NW0TAqMKAayrjg77w18=J+pP zWi_37rKxCw$Dj4EQVdTt%TY)>^s_TvM-U7_k!KAnM~@y&BdNVWg6P*~if!ZihuNPp zMDV$|bW=mE$E&XVuQMbVmy-)+L&xG|n@bH}!>~rA($u^J2p}sJRu7ahU44;bYn&@G zQNPyQLeB(K{itSW3xeEI#IN=0=NJBzHIsy*$BZUQUq1}EB`TIah~7s18A1z< zvEk0|l=(!2dw4Y_XbRD}{LZ;f8{pC!7ME>yU?Nc9d<|SJ00H@sibkjDRo`dH#?S1? zO5Mhl0nDquM|x;R3WJ!~mb4>tz`&f+2~gg$rSKZ}pkaPUt^|vDaU|SFjIMn9rw%kH zG94u~)P$g7sLAm6tN#f>k$|Aa?%_-RPC5*=h4w}UI*ee13YO`{eC!d-E?8HO~ySGn)+N7nsRSJd!RuSK;^bD3WDvV+qBRdY8G! z^$%QgB$X?IR+s!I!lm3(5%wX*$8OI|RT=h0I3~7E zMy-uhAAvASwyR(y5q1Y z&pu=Kru^ypFpDVf=~nkAPo^7AW<>eEGxlhmnSOA(FUtR0t4HVe>4z6#(E+eSp53A| ztW1mOAdxoDe!@)S)r{!9V8ugTFWd>WCVkPN25nwrNi&a1U@_qqhrB29XPT=mVj|tz zyl0-wJbsuF6CHBM=k?6Ylc#+#v59Ryi{EFSK8M9pGYhF6{?k}?`?|&FGXv#|1FTp2pK`99QIZK~L_l?TiD0D@eObz18FRo7nb6;p5^x_l)AAyfuQvDnk1;o^0nh*RPKE61749 zSXV#)36K+;8?<6HH0|WAkiQ{X zK4;{E;f;k47Zh|Tmqubbb+5fM2{Tr2>HVw8I=7S^Ds-;krNUVJjbA3g2DhGa+<3pH zM$~VpdCZPoaeP?em+fyY-|}Mjv3`YoL->D|trLIV?N+I323a2U?!2w__&y|NNufk? z@`32%>YMeEJeg;w1Y{oH)AkGV|M7aT7XH03reV?LK-=Wgs&5Zc&u^I@X`N`+dQz{a z`O$N|^)=}U;ohF{*SS%zsDcW{CN8QW6WM^rq4o6e&W;f9aM&L`{JNhQ)NaBHT3!+u2^Q`^V4@e zJD$YOyi!W)UcK`vaaC&JlRshLNbKkH$Li+Rm0E7-9sc5t@LtS;Cyz!Q-aK*0i%mRW zILfEBWqDP6<8aCD9g57?@*{I=7N38%Q9j01K9}6EzmZh-a({DB}-A$ahW0Fw4 z{_Fk1+V4r#e=GO)W?$kD{HZ)5$4dMy zBrYKCT$onu#p>4e&q**HL0nSOp*^J^ZMWK1RB6BKmH%xism)v^(jV<8ysy?AcMeN= zA+d3F06+TNYm5;8JNfkUj|x_F)Qr@Hr-u%GGyl=N(ROtA+>zhkuEZr?`sR4TKBLIw3%`F zjL|Jego~fB4lz}cbORE3JGFCT^6-`qc}NB9FxUyO(*wof3dk#^6JQb^!pF|)&&?L{ zI{Z$LDYVTIBf5Iim?UrZp3T`n~1dM9?+@p+&aNKRKQS$O2q>G+9oK3 z6Ev0s4V%r_tT?Q@Yr)tsFViD>nJ}T&CD99(F4=n0y@WHXJzetzI?}?m+43*BUCe|T z`IquNexOpmO-Qe8q^+%L5)xN)P<3DUr82ZCLBJ2=3q=G&AKw;|lgi0l=ZiO#j?eZz)LVwv|cl!zg5$|F#wF zFL2VSG!lc?$H4R2>5!VCA`?A{Qdk^-aKnK3=r)Cat$zQu`PVfB)a*x@43UVyowq}Z zLJXL0s=y@8aT^{tn<0Y)kU)9_1`(7CuFM`PMB!Dbu(%cm(a9$N6#Q0-PQom>Z~=x! zrbliwTn1@5Kf&$7cnKuJkVuo{4q9yw0;RNlS2Lyt>PJI4Qz2o%@Qq-o&+o_G*n9sU17JJ~mGlC5(APpJP$XWF&>FW5_2K`1^dXb%&f9YF=e zW*wx*8L9zf6vnY#1(cuyMgXZ)BDzWighKW&_BxKKfc(bus!R~YCP0~jZAEY!Ctd#E zeL93gyS%_JN~CGiaQ~Lm>A6Q?wMXec!6OS9H?VeO%&31$no@#Yi^6E_!cfG<5P-2x zI|ZX-8>MIW5oQN;vW~N-Nh}j0v0)V^PXFpXl&}A=-nFy=MI%xNqwwk8@-NFxY(bQ? z5aKY2$b@SS(t(%NDBwcyFa&4!$lR`^*``_nU+3z?m-XWQ-26N5F5;O{`gtPg7L z2Q1mqtzF_uo%feu9ERgvM~?&$-pJl6vwi7$NX(SEXB7aK;LwPk1MN%)(H3|Z2f{lG zPADbO3*ZVgnkEKeI*XLRWFF=KqNT8>cw}q~7^#vTiGzy{0^Xi*o-7FUXBsatEwYAA z--imBfH@{ptO0JB`%oIlG_FY{5fQ3vmt%gqqL@tEnp7DlSS$xP3UhOIoAl_@4#GnX zXJ5GbO}k6;IpW|y(tt3`|I9-o&D4Yn*R4r)0Wy6Jm`C}iozFM!8=30+!XYtptZmBv z&6MLCrga10O@*_AK{JQ+>}wb(8W6aVzN0Zkad4%pz@mSGg{hD@TE>7%rWFU^FLmWf zpeGChzq}vkazy1BY$E`0U(}xv5#F4hPQC+j93k=$lb3jGO}aNo&X*0Yp4a z!W@|y!DYBx7ey6bba5pCo>BLmisbHw7Z@x$i~w&D5UP>Ctre zFhB-~%s@Flo!@-eev^cbH}qM**l%wlJKW#%y9+rjc6^+FZb~y&L70$I)v1iw?0ggv zK?y*z44l!VH$V;Kbq36Pu*=NAodxR#YM>|dnIQpPz_vYo|5bbgbV4&D)qn{en+^fY z1c;f&vmM&ROy54nVItGmlK}wp2k^+z^I21jV*q3__WP0L0BqQp$if=ul(=RBG^z$0fTMAr8@=e$y?H~r(n>-OqY$DR^b#Lcz4FlQSjm< zumOq79hE%HBoZ@Wz6{%B|0WFlbue?@M21=bLKJ|g;T2>|rV$e0D@cXsR>E`lYmW}+ zq}__6sbUZqD1%A*dRJSXitIhB4`mQrL+zO=1peS3_pct9A+}mw9J3@a(6c**22@jZ>TB- z(+3AC&6cG5*AfPgBZ-+rYuZl(raH#Pk`~0UUY8gxwKA zz%dM1%sn#xZjMSCv4HN!wa`Q&8fzGV1mrOSGhP)eCJxdQw=@@La5>Nw4)`RJ&t*=~ znVp{FNspw(ig`j+vjejnqZp+b{yNA94nvx_%>E+i#q7vvT1VuC`6qtI#``~Lj%`K$ z{6t4?8TPN!RW_AAy)Qw32pK%ul)S#$0cCZ*?_P}D2ZGx=gZc=}3Wn`tH0@jG7I1(@ zzw3MVF1$o0tL4G_r|7`W3vPqN?I*Ea2|rH?SZxdKMLZAPq0er1=0}-S?$p4yyBF7Q zS>7)2UplxKb*FQMC|-Kra{bSLapeSRrA!tHlLmI)+ zdTSZ@33m2`kLyQeSw7#yts_@JJw>{%Y}NS!R(5lHud6fp}0Ek<>V2#8v`k z%LM~RXnoCL2Z`MX7`w1F*iZ53f*k%B&+wf6%MZK^MRFea{Zooz#C%S0TA3oaV-5DD zVa9)RFJ7T(wzob~njGfQH1`^KAU83vDZ}Mf=AwK(M z#On~G2h~D9|4W%xB>L(uotELr^TAOiTpMAw`#7?m@gnWv86L4s5v&B0e*|&>xPK(j z0~RhL7H%GftQR{&SAo_VMz$^n+Ot;p2#6`AyZ%HlFB8bm{B3@bgxpWzsE1b{%qsOr z=x4;(iGfaX=!YEVOlI6aZ_j4wIj+l}pi0P#QCHNWAXqdia` zT!?28Cn;$qf7+G#nvWnm4I?WpFANBWdzX&9JodhL=}hv!Uf5F`<7Mg|VtPvHR4qqvDwJQYw?;?SDjhAvl%HZ9cy`tJ z^p~yodL%{y1KX-`M%V040uSW;eRg-@C_{J5M&j4C@n%McIgCSfoD~pF9Xrp1e_YEG zSDwUTLiotEkn4hQi|aVrjRak-+nYV*ma^tNm*MzJ*W?=aa3{bu zi-N$6jLLXf2Ci6W1+@~sLK9uDUuFxhr=XZls@TO3-MK^qF#W#5zH;bZHVNksLR@B`tiRn#OU0j5j>Ay zgeBdIVwvIYxcdPX#}F!H2Cb~(dF=K8OvjyYel^rBkrtoc}7*PL-Wk>%~`U2+j_ zTtm6C_S-A4^ERJBtaF#xH1n&_vv=2|ZqPWqw_M35G$@V+%)xw) z7boauq{ljLB8xbQ@qXyl%#DPHtAN|#fDKh80U-#`voUE6OQbG!$H4hRM($rR3o>G8V*VPfN*xjIyb}B;3 zVzYGGJ~8$c94bB>B6N3L_&o8Q$ql0%EPCD!2)2B5z&c0H z_l*CpZ9c}-RUZ4m^Jc>WO#93k^NZ*W`_^oHxYI+rQ^L$03<%BC#`cz#SFT1zPiQXH0rWxNz5u}2U zNmCX}8O$s#7DwDDGgZPmz)G|Lv^~Kr)9xR))!J|pQm3NtcBLQn`YVrvs1BM5Hsvx* zf~UsJRLpgo@~)&PC=4qO*tqEC1l21j=?xjFXjKSn)R6eY%Pw1AYr0WoqNsN4*?wk4 z)6EAd_f!p3hxfcDn(~vQ%aKG`tx#whnDti?Pgk|SgXID?8ddUH_eVl>9~F+JDCt-H z8c~ybBs!eu+{)z*7F*15)SD>F4BY!1A3DX?u;{&4F3(eT>I442)T8s|5x zjv2dXj2)}dGl-;|eleMQ*!5nvk)b(iX)V)xHnvtzYi>I|tMGTR; zfX7vyleG@bWiH6EqYh)@y2$pE_9~xm&u0!9Ut$>%h&5` zMmPNphF{Nl6Ihv#>#U82-REXRnrj=>tg350Pk?XTPy6`MgKyZUSMJu`9*5YFh(ivY zmhR2Z?x=+PXZvQF_h|!D^Oj|1-J8MMC#_BYMTJ$UznS<%Xzz3Te3r* z?x&*`7iUga{GF;j-?zC493`|Yz5DF5bjYI>{GAmW6LF4iyjaQj-t{waBYCrSX;1Xq zL)VX=(_vdj5ih4(_6omMQO5zZFV_e~f8MQY3Z<1H;+*^Ss&qzm!?zZ#wH$(!Y{-zEPkgFrv{`Z&wPpkX>#uLeh1EPhunP_y{1`W zG~j8eSJ9U}CM$Hii~BHyAOzS$=!OMJ(Arl zhMY#>aL{*Veo^~do3E`C$EB%9t8h`CZKa^F#m5z5eyeifj6c{%WkgD_b_F~JYrbM%mg-*dw zqxn}@#mA)rukQY-DH{7~C3;CRR>P9B)bX|YV*S`H&w`Tkxjh{*qbKy%jVGiYCOYnY zoJp%Tni|UZ)I-k>Q?C}iFMI1GSuj^^BOkmRV1K_T*l0Klm&DX`oX2Tb^5ASQvJD< zGrmWfUUe;oSE{E;-3Gjy-jD8BNMT>Dd`kjOl}V*eJgXrwVlPR{{XDcZ(}k9W>Hv$8 zMVlTEmhPUk*xPhHQ~U|EDs$hZq3`ZHKSStl>*4=i>+A)c)AFCZaMa|5z?I3H0|wvU zelVBreaBlQ!oaM2=o3M2!{Riq2&Ho2P(dn9r{DylFBoK$OQlI~kg;a%e9#naG{EZ64dyKP z9_{7rZ{5@?los_zY!Z2goL+{u&U;W3jySGE;5M3lTR~(@*vac zqS!qz9^mM8gR;fOl3zx>2GL#bUH3^!u7Plxj!5QDkz+&!bC@fbKMpH0V`dp%W5H^PFHlY0zIy4#zt!=uX$E5UrO!ccMWA`v1fEF_7fJYPt4mS&4$ z=tMkSM&&pePj*y6lY#OUR5|BNuWkV-#|!vxTJnJ49Qu2JFJ|>x*YP}uQpAOH;g&R_ zFGc2wC02A2TOKIqQYONHh(<2U%aAZF;6i(_%AFo@6(IzzM^2gqcLf_p@0IKZ1|2w+ zMr_ZdFv$lo&e+*9+>=!h3BalF>sWVzrc${olcKql=^MjaESm5XLnpCYcb5b!O(hab zcyjx`-l1$ulg3!3Wq}lMz3stp(pg}ePPQP_n+ZTzzgcJ~OOV{DWBK($Frqew)f4Y@D-LNvX@QkA86HB5!#IP9*S1>o& z@&$Uk#(ByLBPfI|@THMOM=E_k=s=pa8d4u@H*wD|XbVjB?YGEQvK zf}Wt{GKCiiy+Inhw+rhIk*}GQcU@0hIe=}t?xGLXEG5BqyNpK4h$dusI8BX8fk6Q! zb0}X+sv$t801jAGR?-)tcs1n&W93ui6)_pM!da*?2IA-d*&kUDa4w{9EL96=a2(m7 zH*8$Tw+Pq$l}3@CVtcywIi}Ev8)oobAf1pdRZM~7CQ~k$onKsE52O=S$eE|Q4T$?4 zcG61Leg@(GTDo*YCWTp}6y=Y+@?lTq)iXdZ07A@8gBBbxq?TKy^oa}tH=cPV%S|T3 zNf$3qUDOIoIJ_Q2A_;tCZ%dHD8(?qIV+R9z+DU*ODjkJM3sFed3m{`>FH;KWGQ@CA z+b-41bR-s#Awndg;lywfj0TZY5z@Rt7W|fG2L~iK`dqhFXYjpN`F&m1-Kk8vtb&s^ zEmC#+LxVUW>2i8ew4Mu7h`(?Ac7}}9Q+OoWlLFvQ~p|}v_@LmTU0@5>ZP?5BxHx!+ek1MFu4R70f_7+3X{^@ z>73`ugd!n%y?fRlrmV$bvL1wVE%7^$aI&I!wG{>ev9w}A0lfmXTE{-n`KT5`Z_B6J zXZz|dxvm+!8J$lea!A0bE~BZsoWZJu)!3vCy0o<1f||< zAX`5W?0d{PLD7Ivk^?E}l!H(}gVX&Nx5hQ<<%nux3Feq7TZ;Kxed5dcOKdayJ{FX8 zklABiGo&23ZiQit$=JXA?F;~#gHTeMZQq^m_TwQI9liU%?+pa>O!xO%4aT%D^hGN4 zE(&%T0r#!yH_To8r$aw-jm?!+$Q1E;ym7A#hH`xn#8K?k3WhYK0(*YZ{cvE_cu)SF zq%_+DVgw zDeN@-+pLdg)93B!l}aN)r8Wm8Q1ZCr;8OPMYj)bF(q3Qax@QdeVN5aD-%RCMP=4OM zCrE+k(i3k}+=!H|Q`&}u?C(jRe>~x@)y%dUtfg=wDfMOsEo@{9TTb5x5a-!5GUur` zI~V}gv!7R3I1b>+FW@w2E~LS<_w9G{xB?Qm=BmGMqust3~R=Yvl6YP-` z_mTC*KkM(pZl#S!m=Oz(8*Hd`64EaVr|#YEn*W&2R+^BDu>e>ne>ClVzHE?=JOt$t zd&5(`&FjOmvZjd)n*FKA^KTa1TA>2zrRWmKfvdCwPy6xqMM}+SFU~^N^VvqkIu+VO z%J#!OFbgOeach?r_!CVoh~e7rulxt&7t9at#gUt1f%XTEE#2(1P$JNM+48M`C%jwV zd~0P(dNoVtRtyJh|9Zmi8zEh$00NyFRzL>*2!fOpjwoI*x7gN<+R}t_$VM$>tU?I| z8A~>ar9#HgSFMI;=zN8t|Y--`|QJfk@mbS;vK7e9}9z7x7fYXf3<9O~s z5~8i%O6ba+dp}Nq1}^O1#xz=aZX9%kC=JRPZTpj{;97&d7e)$z`VgWv@kOS13OeNTZ4>HLH_EP*x=}HU739fG_#obKFwD$q@G|uO{?9Y#>bx+lHWRlJ8 z5bP*MGoE-tmeV}#K$jCHYwJsW)`#ktN1>1Od!+ALel^DkZDA7n%=gUwcppQ=60PMQ zyC_59D9TGSs1Bn`GM?A%bX;e7zZ<>z=qFHZPTDccMBuL@utjz{lx`(ufS-@kTG85Z7>AqqBG8T(+R6z)y&nI)zaJe(x>ypwSc>t65QT*)bLc_p^x{NQoWuYC(_p$lxn58(~!^ZbA-maAGqcpDjHCM`ua8Xc&%bT zb$^vtoF^|2_-Ur8Yq{C|GmBN)`RL~0%GA*hQ-ewm?zzmgiEhR((u3NmP}n?0F3i8V zB37x;TlU^K9`)qrLZhj8u%Qy;jIqPN2WlJ6-nQ-&ow3=oc9x3&CmGK-__L{Q zcUr4lu)9Qbeivf813lB6vH^t$7*>konLY;-7n0tCW#o^7iSmJl#T_rdd@^l6;CcU9 zI^dWH@dB}5KPB|(8sy+61lTt9y-9S$vW0>Z4xw36@mV}V*^%+tQiJ^G0@RfxZ#yXS zxI=Pvezzx3G#ynsECBbz9|BSzllBHRb3^8)N+lzW%)|$Y`$i9b^-)BXJsbfIMB?JX z7w&oTfge^Y?78^i@7>hBM|m1->z&>Y6eOYTQfG`|Y$rzs30e&|43)b2^^AtQetw3T z^&)e4ZV1fFP|6X22NT_w#>$Nn^6g9vHBl9+*M;zS7RQT-5{TsdF`lJ{sCjN!>_7%3 z2nv!ix^-kq7DSJ#{d@T~jn46GMeLtsqSGxM3rA?p6xIFqiiG#qpJ-!oO=3(XcB9 z>)ZXk7s)D7RSV7-89!wjCPJ zJu>CG@pIR?(WZ}oeP23wh$WWD*FKoC_z1Q(b>D!)*HQZ8aWOi96nfe#;O|l zL4DXa$H%|(ruXMB4Xz6GLZ^GGjTBex)9%1>kNnde-b?Mp3VC%8-z20rD+Jv%E=~c? zqHg>c1N%JEO!QI+ZoanNsh@GoB)pB!)VTV#>W&?`=x9iH>MS8-| zT}|<)_ooP$e#L7Atw#?4rUEyBmU{l)sXm%KKHx)D_Oqo}OT~oenn`i7yhSFZUy#I$ ze1Z9I$_n(syqEZH)OFTUN5`Exb>D9A{F;aBhu)`-nK&!a5X3M(miRv()ynugspF7|G9 zXrrPPR}uxU?2IIXjXKzp3QvJID1|=ppm;VL3ty#KxSM&tN+| zOzxB{4v4wdfVi5dY#D3O@4+N^o_{ex*J0(JiT;{dmB@``w-H$>B-vOtwSC=eK5#Hv%MgrbRM8(GjY ze2U);Wn6g1LT3$fA)CLC{{7|k`&);NmUPPJW7$4fEbK9f3FTwh0YaT)R56EvrVeU~ zR6Y%c<(K4zlHef}kMzlY5)<>ER+oEgGR~@4x*14;n_O<)>V}Y%59*ejB?bAX_0r|geqP`3`g)p%_KU6C% zmcuk!w5h*7s#GukUN1eiz4!Z5`NR7+*V3NH_^#$oFaJqT#JC^r zj-Kp|TJOZ*{(gJo|NifNpcR=-aV6f$AaJk6EzQ$F1> zyeA<;7_|<&5Eu>WxI#E5f+itzQ%3gJ4M6;Mha$?^Ae<4gxRzKb$eBAgUm?JCqc-}> zjr7v)OBy}D*^Rfsf~?E~M5WUrnEqjWuB=QA0b25-U!US`9D}JiZ~7{=&sXxVRlS zn?i=J$;7kin#g|u8hh%0X}2U?GzSS}AugPh&3X0c@ehdz>Zoe+4(v*NIghf7h*L(y z%k-~#T`wQ`f%;Cv5hHZ|ENO&f(=Lp=qfdY=jgU${ZF`j@%BqtJ(R^k{5yO7$W&mW* zl%zd<7&3_UQzF>3K0RLkdS#GheFXSE=z-w&?Gt!cNmI4(0JCt`f;rEb$Y_#d^~ISn zQ#eBw3s9ywj3yXCrg0DUp=Izi>?*bo$9g>sGf6-ZdE z#L_G=e#wByU?3gBkjbgJm{C3+vHP6^ffH(&PPt@*&d#U<-!i^MrP)t^R=hi#QMIfb zD<^&hink)mnw?k`1omS;3%+wgsGB)vYcJT$A+9^0;bdoJcN%$Nm%4vhGWsgyA(R7| zGg$Hda1=NumA?dG;UYK6vY`{nuyv|M7f!c22&m(<|1zaz(v9`d^%BWHZ^lLgHSm!? zjDZ%6)l;zmmW%@&%xpBhu;d%JLqrmInFdTe9>+%MEPY@NX)<7`xs0ouS*gJb(I~mG zJAahhc$Q5bi}Hp>2LA$vq4u$mu@3P z2DRd6lQ7-!V3|(z*8GpM?DRptiPPE|A&S?1zz>6~-1WqY3!j6OahVsYi#MkAn6}eK) ztCsHgcYpnI7mX?`{LQLY69lXsv-iC@Mn=?_G;@KcIYn1f6#-QY%MGH6 zKIx6cLy*u8=Gj}mzrs!e$8xq{ zRHI;FsymJ>aQh-p#0o+h2fmB>eBb{wJC&mt1pK)CmaYhJ5;*WaY@~iCx*tp8Nr8=W zTq5NQr|8yL$~R6Tv%4tkIjp3(2d{W350Z#--wD3J=#0o}hqXaY?kx%X|ADof!0f$mb;t|IlIcDY(pY%eIByn16fqQiLzr~vInvW z?6R?W@Ci?`vV6w{A~7O3hhig6tB3wleqB7SfcnFw`uGPDp9s(Rc_Ew{(^+sRGiv5h`Q$`)eA$Q zcVhaV3>|$dJ-sLbO%y)XD}re^L~Op>d|yL8BGA#zHVyV>ME{x&%6p?1_VN#bWhE8g zEYXr}Q3#2>sZW?qS@Giy#ZXzl3s?MOuUy%AaWe5m&@sAt!7N)57No?iqF9|2!Bovo zYgXcGJ0;|>&&m;mhOb=tc1nR!c$s@3>JX^hrlPl}LQqjP4pKF5Q?=exJ*}eV6r{$m z>73tF^H5R09Hj2urha`-Jy1pCW{^gBn@04W21P|PAxJZ&O*3OpGe<@1PLNhnn^wu5 zR;h}1Wsr7ln|9-#c8iM6qaYmxle~^SoxVBNq|FCw8{Soxv%aG`<#4@$HoeAcx_?t5 z7aT56IgnG$^h&SlF9$KECAtI=xnDQ3zwQ|`B9T_I|B=)-0JhNGo`7#nR+ z9v1rbo2EUS={OwMU>R;|1&L!epU%6#qY|+|j=g{f={n+DHq$T2MycbFgLoDiiCGB; zl2x@(OEG!4kLTLQ_wL(a5FAr0>@ENdS;~3jX!3;f_7vLi)w$%`@nn`V z5{yWPwc=T9=(Z}}nV)feN?5ak9|IwIdgUYigTK(&5DX0dSsT>#MY zWTZMRGM@zD41u!Zpv`#OGeEdHm3e<3DtaeY35VQwM2O--2N|9PDexGXxx$1+9mhNc zpf3Q0N@U~|9i30QgLU@c3$bt~qo&9nBKYupDw_Le8{N^Ph3esyd{N=C+wc$X*A9?D zN@JY}R#qNlzoMLpM@_Eu65}RV>1>LMzS9K3a~|xE@sQL?Ofr>K76i^F3;NhK_+nyg z$Sfx6p|=6lu@VkU#IyWS1!!cHGaX9bM?2Ho7VzG0aNeg#Bn_OH5}t)o?~%tL9l0S3 z^ovPS%wsq}6d$001N~Enf&qxHGjAZ(_Sa+oV`sNODd-dlB1(eT-~e_qs+j~8r$aSE zU|<|niFR2GKtO;%t~1`HA>kjS5MCbg4G;HH>T3PXZ@)%uWN4{a|sI zIMl^ku-CVWG!j=#p|S*deY$%jUZmIq>ZYiAH&Fn+BWU-PUOa(?;6GRx$~$L9{|kv; ze1dyXfT}1&{cMlvB)Qj+nAric0&d~w&uFm%)EFtX6OWD$4D#p?sx*m3#UgLxfDRI~ zvS?~`M=BQ)Oru>feG=10b{D0Q`VJ&o7s4)gWS3tB_4Tb*`19SB+w zL{z7e=C%Y86qsfaEWa@2Ls<Itf;jo!7k?e3N8W$V+yPybnhl`lt|JvOd&jKcwT84?#kdY>M z5GU>~YT*IsZNVend#-P9xX=Wr`uHp;yi)|8fQ$T7eO&uAE@@Ym=~5mrfoJey^n|f9L%;nDsVoBZcj2B#RJ#3X!wjJ$DcvI(MZPQHwqeA7L-d^EYDJM}SYYO{Ol%hA-X?(~nS>EGSce~+d? zdNZ)-8RniDmcKJ>db3>7vwS_XLVssP^j=6rzmVy9q44*`DZM$h=sB&PIlaGg1ig9V z=y~&=dF#LPr}bVsMZa|Id3pZtOAozQm!n^K_q@9P_f??Y>zmQ9!+Tyw|9wr-TS$mr zNay6jHh z^L<_tEIq&Yrkc_Jp3ctcQ&+NNIubCoeB+{H%tFs{-?F}?W1)KcyLzWm?VH5#8e`BS zdhWi{u>`*Nrm2WUs<>0pAJbBV{>q2*?^jCn4wnsKcitMOWMkhEUAe4JIfQeF)ctpN9Ep?-E0M7ex$RYUBW^m6(&rH$8}q!qge`<(3PNHC z%&FNI^*8GC%6y*PAg?1GK?22S?is*oF4rFJ?X65=ce!y-!+YaHo)c>IHmmSfftR&Y zB7~d-_VVCYgl?YyS9P4PzvLerI{(h?<};(}e<7?ScAr12&vC4ZAVJBL&5W8-)t499 zsXV%uP{=-k*ul+P7wBA~ch#NN&-_@EkpVeU1RQ6-9-qIjxw#$pFGKT$(P`EDiuyZu zBxP=26p4%#eIy>)rpUz-)@HGUym+1-K9qH5v7%B5TG!UWSg^DVVJeCWT7vR;R@ z-sHRQzo#K#USmx|hZg$bB2xBy$$O`3~ zdVyT~lsHrpbV*cd!-+MQbA~PQ^xqoz)$KQrBosfN24!>zvDItMeUKyqHiLL}_JS3$ zoFFx*Vs%M=f4jY;Dz46Xh1O~>XtzJB^gB*qTAI?|q_U`%g@_+jb8n_6YLKD0)NAl< z+;OJnuAWm;I5398*_=o&H)YZjKl94E#)CcY09<@G9QK}Ts zI3#AX`PsMF0sFs4tZG4sz2f3t&c^)2isd#_@Bm~=A`&(9xZCXEARTXB} zObFvhQM(^EY<(wSK=c%aH3DCn^rC2^EQ4vs3&^p#>)HOo#`5~3R~OP6+tqeLk8=^q zw2K>gUf7T!ElIqb9cJB3DaW2kz_4?Xsr^W~%(tc3_bN>8@JYklziC zs=_^SQ#D$fIw_jR+HF^W_+l}u6U@fWwVZ*4VoEmSRyT4*7N9#HtxX#Q2%5gydoa;T zbaxtFtRU*UHFm~6Q?51VvU8I}{*a{k`a-Z$8d7Cj$p&kA!vwOzPS7-ev zA9*r+UGlQ2jE|h^(1<3DD9({CHQC6WnDx82b2ibs=qD5T;o`brpMRYen{RWoMr~w* z@Jnj__jh;5T^uNiCL|LrSf2V_D>>P!6)y?TzWh?ok_|6Yw+*mDjg-zFTMM}?H-t}V z3hg2^#*Og%60R7(zt+Wn=ap;<<#Xp0n>0C+ z?*)I0rekYxCZ3VS5f%7d<1C6RPnLwi2wF8aPLq`EjPw7BaSt zcjQ@Vpj`0pMfc->Jb1RLhh(^XI{5TPx8PPllJ0itBgH`0GwCY`H@d^w!PiA%P%604 zYf-sl7sf&D6G%sp58iPVnUW!F?s&tK?K!fVY#^}Pj7c$gXHfdsrX>}W4b_+-fyIL_ zo+A%1iw;tt8eX!%C8Z?Ihz+k{#%y!JIUrFhEJZ)89LyXrq- z1>R|@7nbZ`%REmvhqfb3)&7tWXSc^#o|Hq+f5ibOQBe#3H0Mud(6s$+R~UJ|S%*sEn%ysJAnz z&h6=Zjo!9tZ|CdO+bhpEUUNq+E{x?rDsF7Neo|*~DYoKK*Ox|rgYm`p$k2|# z(w5d_Lpvv~Hw8UFEpJ$acFi|7-F%p~yzLYEbm{m@Q)q8w5p!~A_nN}P@aeR7`AUrt`$N6~*MO46W;J270B=uo+^zE3|M#+^W~ zAS}cBIh&djPNuJ*uZ0Z=er--NK(Auc!Un|^TT*P(S2^p$7|HdPG)eYt4Ot{wQr3KIYiedgo#KNBL{vfKpByNpM?YHxbf=%4ZV+~%Gmali+nTT z_qgo=%NH-p$hY%Nj~_kE_~Lsla&hVF<0ri=Ujx!2m(~=YbWUe{4X%$|-u8R)^gYYB zu<^)u`%O=J{*%xB9Qpp}>yzGNmK`!GiVi*5(TB<0iIQ&cTqyD>;8mnB zf^vX2iUk>s#NodKkO{m#pdZkkHA9Co?L_an{D`D_V-Naxo+*U~fMGVaASN0Kg*KzD z$&r4KT0Q#?YYxAx^e}wt^ZmQ`kE1r2-(MMkQ$T~SN7qhgC%qll|K9#Y@A8b&(Xyq% z-JV}PbV~1)fvdt&cW&vT8A>9(wG|YaO5^#S4R7fpz`YRh@Sh_f)ntS3pu*_yQa|G5 zvPCd%JHVe&stji{Y@<4cK#tJ|j$S#^ zHe4SIc%K`uHd=Ms8q(f~LYbfkcM*Fcg2wb0fv{Vq#2UqEAO+d=A`}4iXNC$m2;0 zkj4t*V(i0?Q!@)W7}g#?a*VXyt$>a=TWqo$onqSzGr+}Q4xp(AVMZ>uwC&;-pJ0V| z$gKwn;mz_)h48TNDQ_6r-jS=u*a+0lmA7Z2z?9gg4kJnc2xJFz7QiP8IVw$~;<1!l z(%5G;;r%0k=U{9+KI%g<TqE!0$dpWmlr6iQIV#{MAc-lrSL7)TrJlO zTPTRGkaE^Ioe2VBxUxZLJd->xAe}9Hj8NcIN|D%%c{-A+>5&Bj(g%M**EDXQxp@0W zbvmds9gR!)ZN}so0Qy&*#)Xep3V=8A0DJ-Z%}*rQneVJrdhs?R;uz&#at@z&>VnyE z<}ZzKh8A?#EFl8V6jPI~R0Q{=L$T8FpIox6J1Eu&(6cbmCD(j3B4u1UTeLIZyC?#y zL|N5{;y~Q$(2Td>yOScr$60jM7#~}%!FTtGDVCaza^d~pViw<*^r0{dWmZ(|%{%m~ zK(jB2nVOVeTUe{bm!5Lfb@NI@_1%{6a}Aqb%`*3%bh@^`@p_zcugBZ9Yt*ZI^WFfT zE3MP3-@JHq)a7}t*GO&g^yrz1BCjdtl9!#%FH*eby-OB5ofg8q42DZqM$Z^Y1*uBi zU$1pW;y|DId{|}z72ywdWghIAKltJO;8)6n-?b0WkMB2i1|Bn0q3aJo7F3weF%_Ol zWv-*5#;7b?R1C6|O}3Q7qLj<0lqa>6udY;JtW;>L^aQd@M7B)KqD;c4Oe(cZrmjqG ztW066>?E@Mlx(?*MY)k{$RaaB1yz8p2ja6OWs`5ux z2g+6lSybQjsSZu84zH_@9IKArs=kG+p~%+6S=1!>)Fh?Wq}0`8>=nZs(pa0E0wJ)x2UW1sjE({tF5c6AFFHJs(Xk$u5Xd8Z?mX> zrt zYU7)_#tm1NKY)d1A9%MJvtGu**NoY1R_kfToOsme#tmP;%kiKY6XeviQ>V5y*7W7> zWh@r+2d~G5YpQJL_>|i8tE=hH+sj#0%#k7cA(r)5Kg$6YQ`sy56#yg|Hw@r7pki$K z;HzZJCV;e+!5TGVDrZm!0j!>MrcE;D9j>_;(kl8?LNcvYcDz*))porV6OTu;rxA^m zSlAa)`$?FoX4o1TL)ZbeU@->)ET__%^?!l{$HBtwn9pLzume0xA)ZC*Y2Hq13%?w8 zwM!zg88e4Plu_umOh`Q@%{4}X1zKO*f%=;u+#*B*aaSMXg>z$ z0D^8HE?i5-3)G*0M-oplG-ahjtonE}#tnG7i+kFBt+nG2(REFw$F1Y@CG$Og;AJz$ zqP;s53kcSCg92C&n<4jgJk0`{uy)8p0I9JH>!G*)p<-$yTlgY5uE@duG-D2c-mfU_ z$B`^xHpHQl2K6(OJ*h)*yyXxFlXUAHzjxdVPkRUsgdPH{bBE9VJ;kKc0Kup71*DES zD!jV3NB23)XW6Dl_3%S7OGp4zFzs1=8fVkB)>S%0ht{tKD1ha$@#J1`X)kj_zuHVc zGcdrdG616XCPW$>q2vWWLv@<_)tV(%>x48`j0FYM`Iat)G-EzBW4hb=*5|s`ueERm zH2qrZI;z7A=K^F-Ku3N6)?oTq_W6Owb4Hp9Ui|bS78q>CypY2(=M0UrOV^-=^qxOF zZ0^t?3@7h!C8j+C1+X0MAmg(~4)KZf zV(?2pPfUH;p8AHK-j$!;vzq?lJN+wt`ggXx9 zCZ|On&tO<)*%W3uCTCc#&+=r<@-@y1OwI~@nLWYsLPX((nDq;Z>o24-UdS}Qkehs= z@a4rxmbp_3b1K$zYS-s9GUl`z=X56L^uEmPZ8J~e=7XqbGH~;gG`N9+t7^bJaS}YE z47Z*{r80(Yu;@wr@x1RHz(EP|j68243q8nS8gD)M<&>#2 zp=6%)*M&J7h?_yTHgj+Vyi}dx4bX$%=y9qb&&OYX9r+PV)PrbyFh#QDq=+mempBDm zzezcNCO{97%rWm5&B1WR-3QPkG*ku|nym5$w6j1IV$ujim|kbnqCoR$sJ@w3mJJ-D z0rOAnK*7z(KD)Q;5O9XwVm$-h1p+7GP<=R58~|=&SyY`tJR>c(2m#(Zi`@YTKC)u4 z9;B3xdPZk9Zszd7BWYil8x^qf0rRa`P?X)`mJleY895(~s)~M7cwXW3Bntmpff%h1 zE^&t6Vx`&d?Su7IKLv@+2ZEQ>Q> zkV(&L=sR@Mjw9~ET7JNMwGb$==XI~bym9vXKMD%mWcpe(M=<$=X6fQHV8POJo`!D) zWxoXzUdbzBp-pt-8T1IS0mw3QL5Rx;HZqqpZhmBEJ*@F{_l`Yi2L#neFv{~B z&yWrGfYKRsU%*>tI}qXgT1LkDg%YM2`_(uS$XRuz4+qZehbw;tQ(}%^Is|Z7oquI) z2eK4=NuzD@(V0W0KAso*m;@*Uu&j4|Vb;h2x|Y!-MeKE9-~!7!2)B-UhmHXhVly}5 zXV)ipmQWYg^lme-vh!Dkfe4{Zjg^m+_z&PyE6-v$9B}jZSe8qHtx4dU1{(-E1^*IH zZ;IiFSVsKIfTovlm@I$O$YGkyW_miM7AuUlTv|tEaj@Azhl4l}F-tT03mSdfTD#jI z+PhCpBE*s}+JRs0Z~_nYzH01#(jd^`SseUL^v!2+INbanMJ#OkwT8zVO_8tQ-35mX z4iCFmx!}*6fU8+j7Xxsp0wK?6@JazyUPC_ z{mOdX+WKd);&-=m0Nq?Dni{mV9&9nE1@4Fx1oL%1&Kf$2=^pmLi zW@P29KV}a&Uh8iiKKm)_zXSHzeiHDfD(jE@$zLM@2pt#D`%DhK-e12mIWA#%9$sIp z$@)`|+fT~U-#@r zcK!qkABNo8PRjYpMAi?*DA2O@qHb}-W};n6|J?_$%;00RxC_?2?Ftu^Td)PUQJjK zih=^(`Q#^xJS>8^;)+)Snffs>xZ0vCwsw|cw(f~e@XZFta$#Rc7gq5-jJU<%jCD@zNjZnm_$6jC8x(k<3D8hl+c zk1FMvgpA$rPNZ7R!WQl4eJP|^!blx^x5W-t*|mN##9GhJS4CWNve5ZCraFz8M01=XO1a{L zwwMYDK4r#}RRSZJx=h(r9Gmzx@i>Z+=9*k=m>jO5WlZ#|N<8c7n%LUABG;(3WEmn3 z(VlG#js0pN-BtE;oW$iR@5-Xff31DjL@;PR&@`jVB2|<>!pFo+Kl}EO^xapvAG6t+ zQt?$+$gU6BcyqkPL6i;rNP$zfPt}uHSxxAe(=*vJHut;Cl6gw(RETN^e-42vBaXVl zRdzQACa*x;h4EeBFA^maNJpQsEEZnz(r-3+%^DX0i5sO*(Vd(Er&re)nv~~8$$5rI z7qiAIQ6iVQM#+H`Q)joEKb%}H-Ek5-R+w)9Xm)a3uea<=Z`s2lr z!|NR%@+1AaK0iM6>)v}6>HqBT=b`^G4Z;%@(2vqM3K--#6BYPeAoM73gps7ZF(&uq z=*EP~>!_e9onJ>mGlo3T!7nT|{szxGoQb~q$}RNo&4o(^(IIcIJ^3556!f~}>3dzH zO+`P;7r`^jX}7wQul-&afmxCby_qiH&}1fUPhb>wGsWKus%;W1gVsJ!jyWn4lP=Sj zJGbanhp~Nopb((LmQfkBDn4s(<|CqV@8<=~Es0GFChi3T zMCSG_&1SsZuv1C3lXs7gjRTp{1WDp)_n=hgTLf@=Dz)i4L-q9btp%Xz z+2Ay2%M_C;eBv&lH&%L#C-g4l*o8^dh!j?)$7M7EQ|ai#l`(6?HRHi%fsG&V<|y8M zC=`3K1n^3Qp^9Rq#)j$v+_$q(qcV2*cM9najoVf#$A;8a1=|6RXT;X*IQ*PQ$mgp=aq>XylK?r8gB{O_Dtr-=HiD5fO7sTrfV_lO zt@S{w_$%0SQaZb85;hq{?nCJpD#^sma|nU8%qWEb?=yyFY5t}Gf42mugO>$!RX@rW z-LGmqf+J*8^Ce+4dFl8OD^(>JZ-NIB-72AY)BEm~S_!*2+_)prBhl}jPuAYi6qL|j zON?k1aaf51F&&pR{lsPEyVRMhf94R3m6r&6)7npr@)|>qh$_ZwV+k6DY`l;Bxhk*- zuU5X(B&FoCKV>yh?cq3fMQBpsK$y!xx zb&V3E0#RaJj`)2~pO9^a`GAR}Sykb6c<$`LT`K}qw3+6%FM)Dbs(_vnOa`@q(bysw6Kq{PUj>vQR+d`2V1 z2UBd*7Slhli+6%gzrG4zjZHo%W1CaH9%;LX-u-d2#duVTg%_9onsqJJxsb^A=WvuV zqn_+}xh8ji%^hl63cj!=O(45vKaDRC3FY(SzaCrpaq3CS(vY|pG16rdM(#RQQrmU6 z;=E6ILBA%S|J6wyEFwTz^n9>?23y=)kaEE@ajP#e-v!8byE|}T8)?cUKX4)bk!W|} zW*l3)LNS>t^XfL+&3FlSwr?F^R^4wcc->{82TXjhT5s?gn z4Pp{c?$W$=Nf*U5T*snvi1_~D?5uJrROCAwbGK`(RYDyXuY7j2Xf`zXGE!wMZ$K0` zYYKX)QFIZTfA2G#L^q--9@rC1ipe;PIE2mHp6RRjv&xDp$&9Lks_P@0w<7X!Dh(d_ zEw`_d+Qh*M`zcK9cF;#N9_b5h_6}Y%TpLVOC=|Sa_hC;}EzIU&8=;BEdB94TfZP$B zF&n}a`o_!S1$WIf?gcH$&9M{OhnN)9&8adOd^p}sg~(XDPQ{EvOGX}#w)#6;K}skppj4L)4YjV zJK)B?s!ogfWURg?{j74`G*9H!Vn0|tiP?_K9LGlF&)YaFkm$hy?}xhsYv zI2RHuiDSHIca--F|IqC}<#Oh1gGBJ1!J1d+zMl-IS}L2=jv4G+6!~EG@nnB^UYM|0 z*@LJ}>st}?)fax$Uyc5J{y1V`_`=V&>gX@mZ$&PxU-n?elQ>vvzu`% zYE8=h_xRPAy%I($)ztmZTy@Nk##_-g{SEdY%N3F5)>c!(|@YQ=Cm;F)~!@F+YY z9nV~hM>gP5-FWl_o@EKox{b#i;jw4}n;?N*p1`3?;Itxeog;Aj5_qBryy*nKVgi2y zL72hb22qd( z2|+<_PX{FH)ywXcpvP&TvH;OMPB$_yHWGzW2-G-5C`j8SUZC4JH$H4bTf@2diF!3*>t)`8)u!XfSr`9^z|{H3mScd1NiR5&w4F>FhXN zP6M98cn?kkbYZ-6O`^G7{N6o4ga%f`f<<@-h=UYK7s_tia~@4&#@Mv93)q>nSAU!M zT`pdWW*p*c8Y)Oo;f;r3d)cx9=Il7W!agF70p)}SCdV-afUal9$t=Lk@&E-=yvGb! zPSXH|07)jtVl_d^R$wI;3YT3RGqx8?1IgnIqwJPhkqEQswRam)hrZ>}3Y8NxWAaZ;b8bt4Z8dft)upP?jHJ!VidJ!OH1izhE*G z-srnr+-+ZDEyUROa>@m-(ZVB(X7u>KHY4q30In2gJYxty7_tc_1O zR|=T|d3!azVD_p*yOzdquUH;lgF3-p9&DVCuHo*u#oj%N2i9^V-Dkp3NYzeCET>L5+fYFEx`chL-9IJFxD z^6)a(BAYDJ}4kV_8SI_U7-4Avog!}ieFxE4U$E9?NK|YPbxU5=sBobJE)y^ zP`~b=5$&Lv;h*q61>@Vchg~~(PPHg;pbfD(H^2B~h z_QE!{K6BXr=0>M-k+NZ-uu|3!^04*QX?O%XRw18!U#D6x?#lT)?cOOh0vGy%ihepy z+Fv}$I~~#*zEYf!p5Li*i;keHUte|U{1{|@ z$YU%#ssX7nKH!|@>c7Zm^r~F#8LgOYSDe?5$aXo8H2S-m1n_0EaR{IKQ2`fLQ}8Oi ziAyoMZ9aFt#vcEFSco4$m;rwP_dmn?zuem^GzcTSy7cC<|G2kpmJp}@}-yZxWFX!UuS zDjDZk)n z;hI_B-(xI_XjIsFii;l3e;br_@6%KYtGp#i`w}?fD~U4wjH63<^WC9yul~EM;gmBw zg0|CVI`e+6NeQo6KR6jMda$y8S7^C%nCA8bmdxQjK3i}%R_`(?N%*cvQom4W6qATe z%FyW*Z|OC*r9{1zgki4MQ_q2b2(-yXJI}tv{IkBDFah#O6EhR%Fi)p^;jrL4AI_Lc zJaTlfWf^t&pR2+S@cj3o52OCa4b3F$$N&ZPC7^}0<9TWSBfe-wRR)mdey;TCvQeBp zwNEH?e?F&d00P2jS1j}eT}?8JbGNbZz~}Vc$#oazUJ~Je87D}uZtS`$8Cq4_mVWmv zqE+NIV6)1!c0|ZRWh5@;?9@}V*X^j@D`+a@D^Vyyb!(S&rWCI0_Z5np3B|4Gc!9%s z?ZNZgV^De+Fx+wPy_^k7t7II3-Cby~0Bg4m}=3nO+KkXDhWK0MDn zA;a|la#)l=xB$NY#!Y&M+!u$yV9%K;l^VvOdGw2UTmDDf*iCe^|99M4S2A@Xw#;T% zC}g;h{WiU`t^6_>;tt-(>Bou2$w~F%1Utm=LY!RivgGpW^*(^_E0oOdv}Kde#8H^1 zOqC;4c(KOJTuLIiwt@NV{*nTQXF&cdOxgA?arQ!CKalgK>#2lXVKC|^c{qbm2<7}N zL0zBn&`XiHcX|7O#-&SE3zd*JEIPg!d0XetIn%rYo)A< zPkfg9abcpP<->3d2=w1WHxI(g*!n{M-TZV)9D+kwdZf7&pMb?^7xUuEj8oAHK7*Qe z<))d!hU!*39>aHl&?U1syCMX$c(e+2)=&kQyyvCdou?TvETng{Vq*tSi({1u*;#ti z5=7^@`=7H_n}my#Q|;~M?0`rk>l{&x048k?qYZjvOUAGX_9grr6M3!b@`epwx{Lst z`YhL>`Lh2~TjZ8|$$SVRU*g|Q;$&9dLq6KS(*sU^kLBCmI4#FNRHDPD z8IoZrbShQ%vKI1WRO))_`$uT*&%Z^Vt=sAlQ}~U?LQNxM`9@|24fm>rb+wkyV9g~< zb6!}SK=5M!8$&fYa$bRE>!q>&FYPil)hCe7Q^|O|b}vI1qs#b3i`b_C@>R}T z-y8JU4KkMUg88ANc&=yHdZegYlNgF?bcH3-Bt8Wi@E*jdPzzc6voXD=G1rleI_4Ww z36%$}rWXKCg4L%!(e4c0a3LC999;Os=#m|J%r@eU8fSqQ?+q`D<#mOwynXR-nllt~ z%5Tfp(?nS2q07g)rK=}SmD1;)3$9P`Mk20UTfecqB;7ue*Ox9d&}6aN@jSG5a5j)G z$;%p6w|QFMb1e|!8Fr3TAQU8+$9}cIwUW#Bnzu@E?2oKcP9fu~mCQnBfd>|58b5zn z;U&yC|KowfK$3v_0NMZg(K31??B5fsbb!b#Vq6$XFa6iV^3gSHx-poB)k$96ZrT{l zk+Qlh=WSW}@-eslc&yR$D(!sLTRX8yN?TJUQW1w>$hhJ~MPv+Jaro}3R|1=F1pMLP^5GUDMkPS&JsQ8v=squJyJN?e--dv(!I4nVk_1rue? zN|XO=GPaC$?<{zl>Ax*-{{ycC#)eU7*!1rW!)JB0>0cX$PO^XzW5ZzJMRpo%zDWQp z+!zmL;5GR~_0G=f*z>2;CAb(?LE{#w0Wj2)Ti2(hX6`Az+_=cNl{{Z-_k6+q(6Var z8K}cY(4?*I^>eQ|vh&NfGX_=H-;c+AYHN7Y75aVW&CB-N4wO5fnEM~w8`lOBIb^R* zV4l%O0{KmfO*@)Dyv$QN3l^{=MuUqlJ>ZtZ*KIN)5o)hZcK%#w2-103d`3gTb&+!C z)7#0ec8`iX-fTQtzuUgPAI*`yKD8>nM;R#R$nfjz`1xt+x$nETdmXkPOGODMr>+!r z{rSELj#v$D&%&?$sw`f`@pwG|c>b>eFfLU%WQ53?*tDB1n^)dYO2MZETkCa`nbTJCB-5$BXg5ZsfZBgS(mN z_{e)R-^+Mt!%v9tu}WP?`J;WTO_ldnQRt?(J}gf2=Cx>-6x7>KsK@9Ifh1Up&kmH_N5r@hhfxLr!Eq)wOI= zyu6|l$r)PTc%eX$N%u-m%iQTw*}R?xwe zR!^sDhStN&(xO%FKDA#ucYiGu=g61wZD{>~9br4Et+ii!kKKOxht^T-d@}bhkBz4u z@GXArhhOMkd{G=XF5CnDG_VuJGP1KbEO5_{tAthg3B3jU-s*GhPGk=2^0|H9?*i+F z#*bZf?~XsF{BoHCvwwcS&-@zc3%<@&;G${qVw?C@PyfrGEy1(CxH*3bEtQ1mGSl+6~WT?INR3 zlcQ9=FL_>5zNb6~IGh}K~iu9BFFH9r`+%!fV`BH-?R5IU-_9wd`wE#@p_ zG-eznCl>=x5x=083ku!OA!$-2YI79zgZ6VTuvE%iOfp^}?LWL^Un%Em^wNPz?-8Y? zQvRMjhtpy9V=COkDALH(mCwqP<$#K8AjE4>v{^L{a00(CPq+zvFOYc&;QK+H^bg@c z@HU#BuTPo`QuJfKN7E6kAc0Pys37&sXu-XJ1VL+$!WYU_b1j#l07E6%pqmg66valeTzVlUd(wZKgWsOXp1?p7Q7 zJ|x^S)~--EFU6;rJd1DmQB`zE5ZVRc^UQLA+<&P?zO2TDeCI7r-LEm%lZi_~KCG_O zBwPP<#|z3`tx%^8a22!8*M$ExTlqn~D!BvHq!4S*|0O%jEYtQ9s4^+9<(s27a=%t;Q_Yd`_%MmmrOx>IMUVL=Cg*(+rOECLU#{YNQ(7bc@@zjqhjlUo98J(}5n*Ag@{@t;g?p$b} z`q>ci_mj)1uB8#PU(HYc?s}PbEiX>}YU}#@IUu8Jb<6B`=gQwNq0?P&e^34HJ^K5V zaH^ZmY<|$s|Ic2cdG|Wc^ue&kKi@Jlx;G@v!}vLK-^zQhS^!>8Rby}=8_;sguV(yoa;`kqk@y>N{f zO}|n6okST{M)d)RC;;~cUH|-Qz~Qyb0bWN~)CsoABF!?Cih7G0QI>a2@U|`iD8Le! zgEAzTBKv;!W$2s_rV`F%>M(=xtSxkg;S{!r1ClO;x1a#4E07y#C(PGAD8kq+9z0~aLW;h6-u z3k--yT!IlRc_O63$fS; zfs;l88xD}9S+7pm+;wIA9F{A z;})JWbdv`FDFWDw&{q90zL9`9AY@`9IlYLOYNCK)g0O0|cqjvT!0r5;ppTEmlOBhA z=SJ4>M}3SW!eSH+W6DEg)F?3*DR6{ZGQ-)eU!7z`iM?_V>(BBSOv{%&$Pas+Ti(H6 zX%uIZ80Rn=*S8htA{FmGn&)W<@TSDyI*1QcO=$B@2(3;q?Z^-GPJR*gxbLLn@xU1W z5KH2MEo)3DGR_c?ke3)SmY9B!fX1Zd*d=K$W#ro>6mBPx^70=CuoSWsH!v5L+80+C zC09v7s;iUlQj?$lPHs|7iN&X|B&O`Or}P}8^r@x}83INO!DEzEM_TGMCTT7&Cma>| z&Jc*Zi)33St%s3d$^3;0Y2}o(H->Gpc<0l|<)=}HPYHb0(dyN)4%PAD)rkew$(_}yC(G68ht-*UHQDMl zxehgt!fWyhY6?1Q3YTk&4{Jz#RSb)yA!K9C)FIh z0nh&IaDI2-_?7(ZgpU(w!U1w@)NiVt-mX>C25u6dQkhk(M;!fpnM2_mwiv)mg%Yl# zCMbV>4+sP zs}KsT?u%xwMT4=doj8J{i=&^vrQOh+t01q4Z<VC{_cK_?m@@y;fU_hC*9*+-4iR_ zQ%Bu2{+?Nlo>z`N3lTj_PkNTSdRA9@-X8VPPxyP+HF`H3dp9F`x1aRxboK78^nN+& z-Q$0;ukqrCn(Z#jl&qsT(0cMG5qw zHTyW7`nV(eFok`5-F*V9eL}~5Sb=_#RZb~7>ng5z+yppJ%@Cr)lZLw8=?MK$=Af6| z_W($cFkEW1+fe~A+x6l;m0+1!G9k-ErXt>wSiu_ormKTy$Afr*Axq66Yo{Tb$RWGJ zA&2fEr`4fr$3rdx!)}_x?oPuVkqle!uuu1}-|Ddc@o<2^NRZ}8u+vCL1 zSH-@ zIOq{3Qkz=*(ge_j9{>|rdQg#}N%0cLk;FzeroaT49^igsLW>E&3yX9z1g_(w>+AYs z_srzs<6kzQOQ`5Unr+KVz$(f9E*0^Wx!~M!lro&S%ERUbK%(ftO?pdnL|jM*JkjMo zDQtkLlucbToQwy~nzCJYVP^B{n)OEBqa|(@KE7z0tBys61h7c_VQHdOJ&U*xRG6-t zsKiYG#)e`Z+aeqv0vEB!@AtY=VbpcrNd447V}Zzc0^>v3Ivd;nllnm8 zDvv&pF6;G$lGXfPCz|-5R+o!J#=ljp32O`CKQQtd({>;WIT4*{!O<(6J%gY7HzT<3~x|9Bkrxhy5sn5#(g2jYoyabsXvN~_G* zae+{0jfT5Ql-Kvvf9{YMJ)%{Ri%0f*wG8^2V?i-lL!F2`SK)G1BbFyX4AvFZ@Qx3v7 z0sla%8Jv{#m(V1pnycjuq2)DiYprcDuaiwrIG5g3_VqdPP#(RUvpL{#nY~H7{NSnZ zUCy|Ohs1?bA)wl#!$)WBr5z!%Z$n88%AQ$Fe%>{&4tdd*+qVtYap!&F>5JCA3|O8_ zR*QyTL(GU1XKYxu8LvqH+F1eV4Cp%?27jJxk74VMPT2P^e_VOIAkZBK=pRWF+3eH| zxU&`dx%=%TK$5<*@QgX>cFG@$(_Zut+q8?p^wKy(RnSi9Z3thT{y7+Sibt<_@aOBh zr+t}N7;098{Sd${T$zhR0EIv;Ou~kgt*%`7p!X&wSWik=mp2oL7Q%Kg)JCyDOmRZG zku^=5<;<(hzHCCS-dOce?c|`f2Y66Pt0HzRdGN#ipw3mV&8c41Gepc`G?rN9TB3`1{pU zp{tSC5a(Jx5#?F(+Kh42f(v!dpSTUfRV-hT10xo$Xfh<9y!-rbkm73^_cVcB(G4&#YL$T%2yI7qMYZPInkvl)TU}ewGhB@2{8!~**MQlK%F)hFcu%ym z*M$h?(k>&KD8(sfmqSmdCw{~Tr)!17+%o034J*=i1#51E7#~vpd*yrqhyon`t8y?@ zP^zTYZe|!mZ0!5L*xW?U(WQ=oCQ$=LPWgYax$XeLkll?irkH*Rt8wv$QO!Wb_l>vZVoodk*5S}|$T4}h|ab+yo!C6=UCKfN^bZt`Cl>(bZl>=!HG zjcs4d^O0*ih=Bbu+b*-y@Yc@XpYa&N2~(WwmXRytY@1kv$r`d?NHD*2b2s#-<yJ!@9uc9KElNWm8BC?_b=|``U7nKa%pD z=#}$K&{%?k+ggJ7v<^JHv!v<%ZP&;Q1^r4 z;2T1ca{q$B`a@rF=uw}+zaS7}K=9!LKDuM55_CC?)Q7r*-Z3ck6I;K6GPKf}D=aoH{%7C13jhF?LGS*bln%Gc zXpErO|5oW>C{qljqwqhK4)ZkTi`3BQVPw9fx~84e`2VSNSPmMlKmC`|;lmjAwTsVO z29gCe+OQDCkT2EFwU6MCnt=D?MJB(cuQGJxe<>Z$-n}4z*cy!R34$77#Z*!NF*;i^ z4Ed?r8SN?sbU2UINAm?-brF49K zM~z{-EsY;3(iF05_n$l@CTQN1cwcPRqi+3XfT46u^>qFIstUrNsP6XNy|X#NsM_xf zokzd-c-$meE}QV35vRte3{2R`W_e)Vmw*L`jWFn8T5BR91|a1k3sxueiNV%4q6xzU z?5sRfd=@Bj{{DXH z%OVV1G=WX;hrK0-UtNGzmVR?zT%N4d%UP(ODK!g>q2o6VRTC}r(P+EcS&_KG{7(%% zK|dHlYIcomf-+Z7aeO)=(%R^o)$DO?N(!LMkI~yc6HP*t9Y5c zXRpr!L-heipR)-;##!;l9!WBMwxMFGnQf^gY zFgFIn59hMl<%5T4_I=wTUHH&s-~n$Y=!+U+i2_PsNub0U>;`;1$eJTvg4>UAlfu_G z7Q{0?zWM>Ida8zS-ZXBuBh*XK;?$I|$u?`~X{iosmVtl(-aWr4cuY?R^Sm2`nd zOZ`MZ@rHHj)XYQwR6{sn80d;VlFZc^D&*N?^Zx;+iX<%D5kQfH(R<`I|&UbUqq zW;<32@cjw4JvpBiOXLj%jX^cgx)}oLE)#p10wKf;QfA*u->9YfG$fY25B*k#xd_9s zan`KnyRv&=@nf$H`5ZXUSRwOb6|%vJH;-H3VnN737G zB8ozrLndpBS_Bk>pgRD(y346y%y8e^E%SXYH_q{X947T#%sKxG@EP z`;^I@FzkAip>6$(D>GH{>#1T&ytiYCin&$m0_#|2HF9a=o1YE9%Z8E$Flk{4f;K$y zF5qs>UbKY!8rTj?XKlvDbBa8S`I_1kWoSsK1{l(TeKEMqbv7v(`?Fv<~TXj_EmCsW?o!t6+tT5|o z{2{z||Kd%9kQwtFg}b7V&!cd~SiD*);gVHoneUC4H|S33Z7teciyA&Xkq*+pWQ?j zYdb#pxd-EG9PQH&pXGNYGd~|&QsnvwR&@uFH7xDZCOT^F%9nWD$$Ov1=}Hq|SuX!2qkY2h-aq6Dn@+N6uxvs4ZEbm8hm^%?&g9Z>P zJXxDev}GP*6uiwM>>K@r^BTwP-x8YZ>0ocs*0$x;IJsCxd`-n=ZsUip805;JsA_2c z)o%7Ki=QRHzc8o(CYtNmwe~{mDz3Ve@j2K=K4MG1}vOuh(qWNMThJ3yRdNai~Y^vb`Kne z+%f{hT)|l~U6K=)DI~H=(wShdQMjCw&bSZiy?~sOihv@bQvvtNNxMS8Sq0^yV`=c+ z+7fd3!Zc5_+^^j-gJxm`qQ(hBe+!rEMQ5JJAgGs0ZoV@I%h?*-r$f+L~qV2 zr_fHD^F%XU)_Mk#Odml9=ZGmuV0~tl1+wuFyVxhfLK|6x`ck1Vnh^3J_6v|`sLw1< z04giMA^}1A)o2SUG4r9MS+j&oXkaob!f_NG`AEWCG5$pb>_CqLof#M+f(}yz-42Zp zwc`f52#l7-PP;Pmg5si81udm+DF;bJ0%XFr(U+b^r<~ZSr5_|_k8*$lnO|a&^C*@O zEX1Zopvjf_`MJchME|t$(Z9!{g#+pU1;bE@ zWE$1LTK8O9U8I*Mgc(CxRgZ# z=UvIP4LhD!d1>2u={u^aPP%|E2kBq!(s}Ntf3nN?6`BEtsqaxT_M|fOAF)@m3pru{ zxjLB#p_vT_YR8n!FWVU;oebE&m5#%{bMUY%7#eDnMVQSJ;>{juJI7<6&0BM> zOD_{!gO(jjSDVRJ2Iice$yWTxdtN$Q^<<2P&njCpEIXw+OExe^ML2gbkV}^reIYFO z)Wh7f`8j6N+!|v!n2$N9V43C}T*ka9VOb9)`X1W;d1%)s^-by_o6$qLAf9U<(cZ6l ze8;$MbvzvS_Q*x;@!1Y3ckgTu-qSM@kDdD-L;i3n+vi5FJr1_dlM;S(Z!9yc=CO@5 zIyNjmBP>sdJ^$Qm{#@_8ys_+%{JfhTd0&CK`G0sGOXru`7d-07FYL%D{*#}^f-cX` z$X#Mr_){Rqo9XXeKru?H&M){zDOdm&baA{@|NLQV6m> z0ey#nz}ukjyTG;jiiOXy?iq0;QxPqwBrK3*zXrehzC={GB-|A`AAq>G4cMeQ@VNr# z@i1s7JA8*ElU2;!$+3y|l_Zw(9iroCZ2UU_cmWRv!1gwvOrWEv@O9B!d#)%Ecpd?W zQGhH_HBM{m*U;3@bh3YC!R)gz{Rl&27^<8YE4jMl_%(;#GW&gOxuPqCj*6Erg;;SL z+a;r~ETgBe%xHY&>9ta|KG+$Fs*OES{#^E}Hk09lTTh$FFd1|uYsfe%TDc?A}31;{#Hco0yb2S5g{Gqn(s zQgPV(RQMVWp7^N3Wck{BCZZl7V-t`xfn|2ZBew8}2|~jQWtMpy>5nMVgT^*bW25Fe1Zkmke&twGzZGS*A)@Dg0laTm7d+e1m$7)fq$2J# zLI+3)_39=8HW@}xOIj`41{E=%DO%uws39dHN$ruJ+VybF^LPZ8W&1so()&1g>XS>X zI{+mb+iO&_YAnlJLhB#luKOm~VZN?M8XbIVjVKMtEo`H5K*MLfCT@Peh)mYG6F^Jy zQP;Xhs~wv|A{FtP3j2U7^L`>$yxjTh6QHl_+28OoD=d5-%lNjJVjL-wj<9|O*eVHe z!q*7mj{wLvf>!|WPAbbP;E2q4z;Jm$?_8q}@+IR7n|JN?tbH=+bVL;Fo9or;%hOm_ z0}vWJfC4O%o>?mGnsuIBUtw26U#nk#gt(;KKyqs^*(u?sB5v9-bt#A^W(Gh$*~j6T zunKTH2N*q5SqXKh$%x7wKnkAKnQ@2M4Jcg6Jntgv;4);TQBrU9 zT%HEFuK-8jKpTxvZahZpo zY;CbBkXjHDmOYxF8M7XOEV>DNyHld4Fve$5bz9S)Km%at@LEmQZc$(tp;C`FXf9Wd z0KjY|8n*TZd`uHy78f9f*2kwYa<@>da21eR$3B6b zL@Gdb1!&eECTMb#@8hqJYd-D5GhJP0HL|QiQ)QE?7#)O791C;>FhMVZW_GDH1ydj7 z{CE9^F@#|>sb@=_d657{(}q>b*d}P6K_^s1;OykP0T|)U*F%zs%ovxzHIb5kJ_Ar@r5d^` ze8Q}SG(cy)LeH(Wl8V*mZ_M>@NDu6aa)t4I0G;Ix`*Ba52fYI6QriV!yW@m~PEE)l z>BH)4DCA0W{jACIT3e4oVy4*ZD`T!L^vy}F{SV`J)L;3?`b$I=x5+F&+yyM|>4;Mi z^*pQjhjmJ3%W6@}&X&tYZkq$Q-gu`kOUtaTEA;gELEoZ;?_;lb1#CFfzG0+G2M8il z3D<*#gq3lx>I0$+PHL7y$ClbHii%4IFjUxUfVi&n>wwhe4z~)b2rxAOF;A)W1NfIII8aj$JAwL~UlbT%FM>dVHjdUiGh z(>&@bd)JvD>`sNyyKc=7SBfoP!jab|*pJVYv=FwDwBarPuV2u^@8ea+r`WAXEIm~C zCY7$Y%vxT&Gl4(9&+?7h%f@kP9oYy6ykXh@@QLT0G~emfDF6*g>R8*G;-C2%XpAhW zqeW@$yPo*fiep*VuswX=YM&48^8xpUeZHYDF}Fqq@saIFp52dN*PMj>mEyMW^FUe9(k-xj|p_*E<4 zH_Zp7lh}=ru-L~tj{B=7FDf2pvO4$MtkarW{6DSwi)vmPC{=ox8a1%WDx%)KrI-1} z?!oKN(#(qfAMejYcujOnMf#51f88elAO7RJir46WQX1}{RnWsO{!YAx&`#>C7+zne z{vGlCqRTfkr1)Z$zm(;ACp?cdCUA~vEnpo<`mABSEsp;xi=5@xJ{~R^XX>TBOYzM^ z9ezD|ExGUi=cnM$mxb@fo4@YIvBbT(CKvVh+;o|1T}Ag-K=0XAUjZ88(k3GPhtzwC z{Yn_1bgT~-y;%nrSa_-px>Cjm&(Ue5Ycu;&5bi1lWih;qBFMoFavxP|PJmM_!S#KG z6$i6}fa;a>SRxv8lYa>?*dc<}Ne{+1_wn7r8mQsL@NSp@WtK06=TKyjCo6N+>?;?Z zvMj6XHlNgnR>$s`*{fIonjv;bgG~x$&o$EIlLSS_bMe(Yv{YoU{TsV)Wve}yBNqby z5^$Y@PLem1v-oOQ1$x&BQ$k4f)jLn?)#v&=2ccThk;(&;A5#ZgxTWLIoTK_Jx1QX3 zH(ccS+y8CPea0C+r-Oj?p|npDS(?9sHYbZNB?vj^Nw8s@ywcF zc?eKk^zRwJ;@!ZZ#Hwcc8=Rj=-gqT7&XovNUVv|G@aZXZdZbM%RO_>|C;-4QTI3{S zw!rZIjp~|>00}bML*{a!f|wLA6I!S6G`3pk4wlP7p^=p7XRWwh*=NWkDHpgLL`}T| z%{6437s!i#+R9mz&h5a5`}l&F%+5X}a8IoIa`S|bH)~Koi{uld!XT^`^JZ-Z78hTW z#Q&xHNf7Dz;b?q(4&2=x124Y~nJ1bLWT`r}}1qEEB<`uCGpBpXTkpb!N!Kv34j57t z$CKN`YMw>6P10lY9zfN-N-v-{18BU@M&0oJH(un8?HE2RSs87Ro12$sIA_TF-1T^>QR_;E{EQ!KM?+1&SnTZyz=?=>F zk>dGZ!(!f$&!q*j`$fFrXEC<6eC%!a3|PPqe^F?W=1fUC!D3L53uFt{f9%$XHrg|P z_iZnwub#QBY!R!Pw-((lRe$@z9Y;@UdCT|ejQdl*EKtk7w3~H(m~RdabH(~R5JlR3 z<|iO@RVms%Oh@GXOB2`QIF;6>$y*?!mF4AMb!YDergDH1ZpwueTZInrZ_TY)lP|zf zjSYO|d32l;oz>qdCJsq>JsqNAc$s@PGeLL5FI+`gUu8BcBUbDV_x|XNuBBIwb*hNj zoPZhoMnvPx#vKJ*I>o*Z|48?y%+(HKn>Mu9!(f1fGq3U)Yf<^IzECLjC5OB!KMnCV)Kj<2p0X^L)blpJH!zdk_Nwx1 zoVV#s^|>JOtEvkZrA@p$t%`rWddj#_WEiM!UAAoXRC|6+si-t74NK%-(ygSA|9r0I z^8TXskdIAk=T#EdeC_q~n-=%Tak_|&8?<0(O)UFEXfD>fHdp4D8$DYJC}Fdi0&W5#XI~T;Ws1G#{Fa zOxKc*Ow~C=J9`7)rYf@;EZTv#b4F?c#!M%Dc*uOSoGY!VU(sEPnOqd(>mIBvdpO!J zGU|?bjfsPBTe13?-e7lX_KW)2bv?*u;l;^kgy+q}rvXGgrii_Guv|b|Ad%34KF6%I zK;sb0)UnKh5Vrp;d-6kuUD%C>RbS*mrRGf;M>N%TSn(EEz>2Bl zr=o`!tC32_qZ5MIW2D`6_Hohc=|61bgW1oukKc6~yygL2Q*Fvn;fN1tKOeNi=j260B$c;y zR6}M`oZ&jsppWjds-ru-Fg5{4x5=wIsXXX}tvaiY`g2~T-W%s`h)yUjW(l#S->eJg znIi$^WX=@`^FUC;P*L;V->dhnYPMm83rs=sUIX6%sLzv$+2{+ZH!$tmv9g|_rA|LZ9rfi=T7%p5HwXqc}z zJ-n`ZXGr)I(NGr>@#w2fJn<2b-EcQBgB$D|NVdKI3^Sr`asKV>j`P>Wwb!B--byW+ z4d0IX>FWl1+^+juSTA0Au-(&xmS9C2WXf}Cd9zn_q4&>~u16v*vrM6s!7~kk*Owt1 zVg?FaI4+tHNL2}@Xhnnb9MLLRyn>q4hpY<*^csnS^&X*@x0*+?OH#I z6YiTmd>?M&M&h8{90qv5hc>{c z@s{no!^OpCKUyzBu`3`Q3@~z@>jUs6a8Q;o%F=YTavDD#V=%^%Doj;?`g|<_apSJC$MRewT-1 z{Iy3GzJPZXeSS7 zbH3^m;_Mf$Xg&?^!;1BbS@(}AUPkHmi^uj$!O0R6RLR_a*}?w2vdi$6%keUN<>&ZX zM*s|=9E1u7(5xKkbL2S_-$jMnij5OD!}P@uS#I5nxb z56N6#k_W%4C-DIXZC5q51qRuVrFC)>)hJLgdfw79#D6YPwHktGm#dpk)) zDi#eOx=Mk?#vYaK#RKz!ceYhMRhtxGMgBGMu70%^0YE#>5pvGZiRd5!4GjV?-(J!s z8}?YETAcILlN4GC4O`qkK?cXT9=|RsN_^rYm0w|;Qd2!**EtfXJDMzOaH3&AC_wTB z5r5-UDpa$dXTwfB?x=VjWd~prSS~-Z-i9EJIR^Jg#3ndF9sp3IK~Yl0O=>U81z2+YAb*6R7kCS)oLM3PL!E;YWubh1RH2F?!$`(Gg%|EqnZKk9-wP7;#A=XUV&uk-NYP)4htk8^JJN0S9OlV^2 z-OAJ#PII2)sU^1QZ@T7aIrAlr=^w$SXJM4ZHiyad$0uHA}UkC*W>OE!gV!}EnyW$J< z7$GwBaUw1H8rJgu93rX9M~RaPJu1t`QwZ_5XIs9H0J z0)@O5P^wnUUPMN-{SZp@gcP7%;)m^EYN&X#xHO-h1^>H9B~{hCAAo*>Nt{anC+Bod z`hs2DT;R=$9jOIxzPRD!it}fpd6&2u@emGP>1a%>rbuC%6xd_Cy@bW)PU$9-AcI5#1Vy|KV{&p%bijckD(#&h#OqXi65jsN zWYQl}jGM?+{BsM>%k$UM(k|EmX}O7zFd`xmA%FroT?DGw5hMUH5E7F>GiJUGD(J06H0Rnd(z=><| z++>nvYI;ZgO4sKVYJhDL-l=P7C5r;|yOj=cv88f3_1}aJ2=YC@Ri&m%QBy^4l7OBl z!B_c7779?qG~Q+eoK{rHMOfb4UgCHt@j4Fi29XM}vp*3Hh-D2RK(Jr~JiukyT0Y;J z=KvzA8hsrLlMVnn{d6_}yk!L>Llt5|@@Gnin#=B1BIwZ?RG|Xo8y)1mfXr0jpDWQkMF17m7z6;MB1K1_ zVwAj?t~&$RyqL~Q#R#954d92p{tUS>svOP87&DA>1+;)T;;&_bNO>_fb6_DwTjFFA zqS|R;N8DfI_2-Bat`DtEBK4OzB~6yc8$Yq?V{Zpw@@Na$ay}AL@ia- zy4P@7FUXB0NV^62BG;NRZ>$C7nX^}1TVBjHOni1+qD`pr5NR5s8qt-b?dtmu04y>7lBLL^W0Q|oFQD}nSVn^VV0>P8)D?$ z_dR+aDIp7-hD07`f~Nk8c(1RlGeLaVhT-iXNv)p!(U#=5x-cR{2aEJN|v{^o->_P$-Ui7;5eOc&-RtBlWSERrBKS(+k zegrgpHY% zDWmBocxYD(Z68DDae^G5O+k(_+|qB!mea-2DODHKoeSxPh0wQ8D!Kd5z8?g9NL;Ti zUGHmLZ)pC)Q%jZ3rscxug!H6cNk#ub2lyx`aHxSg2j)RDw#FcKN_1WJJd0L@ECf1P zCAU`s!`(u5^dmy0Qc|yc@aX%P?E$#-?Y%)HM8DgGJpz#%VkDR+!!M3Oha#V^az!3p z{jN7vVls7@Azu{-I3$*(q$erh0r1H0A_fJN1Ym>6x|#>z*5EW3jS_Fj=Bfn@r%>?J zq{2a(B0jpJ)RTMFwYh1{r<%_7>wT}}4thuq5xLIUE>#R1ZSOxi_lTNO-XVOP4GUx^ zFFgDbvj4%r$4g|vYk2MhY%BDMcc|=tD?EjM!#?T97vLg?c_OJ_9~(RKcr5j1(%fQvWH2*=g*N-M1xb-8-I7OW>WIPdJZA`H+MBOe1KZ>6w@0}cNVO8(UI?0h^{m>FkMW4#od?bz$cl56z2*= za}A0bi=5b0lmZ?37Q>BL+Qsc%{T3&mIQB%6|Jk=`C~Xg#6WjB^ZAxIH`@guY;~RxC z;qnic6bHjj-HvmUp6})?Nz7*{xkcG_{a74X{`D<}mFVBk?Y|{}@lOl5Ao!<+klNar z)Mo$ZGyBsR?%b&{hBqrkJOg)bhQZPGU^r9%rNfe)X`i3qe$w$!t)9xJ+pvivzLPij zTBI-K)3bY?%fpq<+;h!JJc6dZI4|6AgX((4mmh9e&gEY#`9tcO5f|^58<7={PhC@* zhvm@JBOw;FBu^Yf4gnO4q+4;ploYTCHEIsK*$@iGhpleO45XuuI5kqYWe2k`gy@ac z?PXJxtYDs6@Q(bed=>XrU4x~OROsQcs9VsqR47zUclGxdQ~R5Ig-qpsvMCrI=BGyW zM5GmRan(7TLdo$Ja@n<7+99WUq55+7lFqjIl3@BmLmJfH8Z$6Ak5vdJ76ERP|LJz+&mCx>=Pgs8u3r8} zwQU5ALKCj9q7T*YQ;RNL_@49(eAi_l>z%H@r^B>De7zv`X(C-v%Xn)Vucf)8kBr1QT;ZO(edf$nuIV$@=$`GR z%zVAbJ_$z(4P&Ki3+^Mi;rk~N`9%wbb==x@xpa2<*H}_brXH1~BchPAHjUzrHVgqZ zTA!x28p2ea)1l^&DQE71yCrw7@jS}MSq*|Jj(TNyq$KWr{0dn%*FmA|%E9mZR{WNc z&S0A!EjrME)eaOO9JHHok#6lxA0md@0V1cv5Fi1r$08=ML;5L1Li5pcGW1*rlO%4U zh9G$cdA~B}70>bP0~xgA>Ge^1R^zz3Q9Rl2*(u*T@PRRU7Tag5)sHPWsdXqi-7rCu zGSL3_tYm7Lq3438MEfANdN`@t8&*^Af*{p7CNPQGEzi>n;YFn(Tyu)^o&s493oi1i z5j~#`0NrySaJnk6%5DPU{(|p2jsZRU)O+WgI3r}c`0QkZx$P*2-rp#4>zU<$aX*aVDOR)5n{!C=nUKtp6#C%e32T#{ei3*Spkz8 z!G))d-N7;(33(sC98+O>*uS}%#Pc!GXF>S}c$NzT9}Xo1U3(4r@;tetcm>M!j&?4# zUqT)fcFb%*hD3Ek818{03nNi?6Ka#BcebE;Yj%hTyvB9@be#8|Z-i$*crV@d8dp3C zB`pNp9zdkopUxHr?mfp#ktb95Iua)JtH2{BN zIVAN7|J(Kb;Fa;P0S?4j8VX8TR*WUuzo2%5QxJgdhdoWtlX1d5!Xeo!Wwf_&UA#NoB56M6P4j;yEEPXdiHm z)(_W`!b;Ps-h9Wix?Qx(af4`hW~SZ5#qqu2c0$)p>j<|HNBM$4$S@+{sH6kK*A}Sv zrQtd_2{Wv_&oDf)>~Xmk>{12&tZ%2Rdi~tQO_(cZu&VRadUP?bYwCJtjrQ3JZ(uCK z|I3f&%Z?wd+SyJNsrw4IwBGstu+H=IyroyM*6^~1in|4HyTpg+)l4csYVnD#h8(4C z;4%9U8f3$5wgdX-(0?C78Z+VgT$Ce9$zt1qhhu|BD!Mw21ma|Of>l1 z9L?)|>a7{tsG>a7cfo4wbJcK@Th=1 z)w&*Y>W$`Voyi*Ns2VMJ(#t-W<+!N;Hogcq)d#YW)Rllqr z^Z2!lxK+WK%d@yMdc%Qk)H}|@pB56_`+|?_6fdi-7&Z*NKL2#LAl^3UM{4I$=XsrS zu=*-VsB1KJUZ+&3X?1e__bA-Etx8UP&C0oJyg+fUQm1K+u75Dzcq{ilS$*B{X4hoR z{zQ#))B4f4gGuEITQ|DVl74sB^uwom%`tYLU3a@?q=P$}mu&((xw~fvkL$PI96_DY z>3$~)eArs0z8UP?{l4?O{=>F81l6ni!~B07{YU*JXTxuHzxyak=$dHy7T5O2{&OPX z!P~iS@e|$i`w#VdcAo^tFLW>b_aA{pZu(AF^|XhaFz6F%-b&HwSroWxP-O<%zUJJs zB>K!?P^URcQsVNm6vtqQtg(}O^DkRc)9{sZ^Ukfdp3fS$CtjY>*u68+^F{xeVW0o? z-ICp&mE#=4QNH@!a-k=y<|mBCuN;p}5nRTeyn0}WFV7^g(O~A5xeNx8D_cwkK}Et% z&08{8=xnSG3^04tj~)_GB4^1?6UfU_qqSquoE%!vQiJe5q-I8w6lH-^2p1s4zIZJK}H3%b0s@)s`fD>`wZx>L9Mjta76ZE?|8PWCC%HDq!{e%Y@hi#Z!-0a`DMyau2KtDxv4OaKxOb-+e^d1yq*KP ztg^q}5dM9f1(h_Z$KV)4kb@i^ZX*U%1jFmb?pisiZ_P9c;jq zBbINl7%;G+AOrb%$uEmi=FXY{V4WcnAPc0ZRBHI> z8r6^`UQ?kcdj@h-^* z26OP!$>OV=c|$xyA4){KBoi8M{&1{R&>lFxzl^uUE%<^Ig=Lj%lD4^sDTOkadS5^x zSsIaSum}2-vWQlcM!Avo?wRo5k_eCd0K+s@23bGA8+|(2&;_gmVPU9bU1$}t^`6Z* z(U4dQap}hh({&2z_yDpB&L05yq+n!9NL&`%2NH6~dh$MG-6{iSl{83Joj5NzSf+ix zQmXWf^yy^6h6%F0(zIp{FS@KXxTH2+DR0d{ib|1%lkjj5flB^BmxShn^lkfPH%hP} zCVGfuzMN%UNU8o(rN+*ZaB;HuF+X|PN?A8BKTg3T<1Bzm$EPP7cCidEn*)S7eY00; zERq5MRC#eDNKk?zwZ0lVTB$C2R?o$c#}c5U1R@X9b@mpp)4tM6zV0D&?x|;yjR7`K z<-=ap5O=ChI4wRuC1XmdC?*~u3!9o3nv#27no)hp8zy?fbjSvsFe?y|L^ISMkT34j z_XH4z(26~kii0J57yB^~qRMI#mnBR2BZ^ktr$M7}!Ta<+2C3SbY`k3XJ8L&I5nY?sr{H$B|@x{@q4-BeP@vQ{TNFC>fSwwZf(>aiBYh2r)EtU%2EzU zzEDFq946j5P6hOok+Y~jH%)jv0N3?tTv*?>JPI&uq;usT zCU)Mx3R=AqsIcv=l=%J&b~ac|mINlM%r<#v&r`1#QJwBl1u-&?iGc>J1>t;hT9Tyf zM$)E-3M#rk;J+oYlWT?6L=|T3oE~6CrZ#DvQ>$%c+IpUf#5c&=(jh}Y1L}++_H&3v zNR=n6!Y{Zox`uUKvZHb}sa2Vw52zL;T|U2hsi5Za`28zVp@5HHTlE38pfh?s>vxNk zi|UnQ+=^q4Gh+L!UOOEz_gIO2sAfhzLRO;i6esf)0u9*S(z*cvVu%bn8BC!W6nmqf zG{r2FcXfGS++mq8pU{U8CjC`^%^6Osa)0^l;58;Dc&@sDw7LI7qub$kd5n=-l}0$;73VV+s$F^WD~@I zAQYg37_2E>`Wo#0rmN{zYtsjPj%i^5fKWWAH@s4(ZTiV)?7UOSOl#_F<+l;cJw7N) zm;FKmQ7d|yyh;jD`ETJF-+s2O@`&l4NquTq%`5rkX~|8GKQl%xL-$67gA|)pUG79;>l%5I*%v15qUT9txPW{+9G#-F9E)ciwZXXdI8p zfS0WAmkLca(LUW@P5%Yf8_;}Nl@B24eX5?U`E#49P#H45|Bnd+vKJmQsL;`=#P@j3pHKh}Pu2v0W)(Nbn7nr29y79X?XQFp!&e)|5TDR;NKJ;kL%hVnTZbsAjtLO zpy{1WD2j5ZIWbU6M%niVZ+iQ3_N;A@dC*8z=Sf$+8H211$`%BbZ>3uMbsE6*y z9;nnv z#uw6OQi9hocyvUN35Wt4|-rneLc*Wdk1$(lKXlsxPRw(a)s=kiKatjP(mbCaaY?0fTJa&q+^0bw}P}c zhEXLjnz(~9c^I%* z#POC=O;Tj3E%W9tpQ{48w=Q-3crUtrBu1Ym{*XKhO1$W!H@U15RIQ}@$^Fj{^2hV* zfoISsbjfODlfVWk0t25M0^X3DJvneJ&re|>B0O;(~AHW*&N=q@(!`4#5} z+=Hbn+;=6U*AD@agM*<&AD(>j(W`;_7qbn%rYJq?3mOHiwd$!moRkSju5RBM*4V)e z(;zgdGlFSY18_?|;IG}0FIGPaF8sdSOs|&LA)Gw`Y%(6*!D72gDz}w37!I4-`12UEfGy8rzL39z3NJj z%0py*D-S(l+dP8>CxbeH3koJZe-GMm#4s-dJ_H#Af62e($Xpez#8^RcoHZedJfe zo=XOU5|2S1u0L41qd#kGW0jYD)kfDWs2OPA+ZY7aAs7@j7;YI~MmEw#Df@m2D+%*U z_&t;0=x!ZGZ-vH4LEx<40fF%VwVvBz)x&Rty36Lq z`_HueF>1Bn&r&^|ZJ~EVNdNWD)(x;$@QcRS|F*6_vvR+$K|58)_XtF|NLFp1g|EuW zQA@zK;P9)8I&5S6nicueWCIx4pvZA4rhh&{4$U1!QtESYd+l?ZqeWuZ1e!C!lkp@E z;*#cnVg>5*m-w55l6Ba?wNFu22Tx2UHhswZ?}OJQv_qvc`t%A+7Wu36(Q?{8M#_9( zg8;IpAMKkv_`8=rAppE?Q8_d!aCJX}+CCjSap{Lw(j4^-OWGAz{iYY31H z=+}jtDBz$g_WgfKuO2+Oy03iL{D3EQO?h(2mkFi|$zUQrg!0Ck1_*s59vk)QZl{|L z99r1Y@V=b{4YCCvVUD)D72-ugD89E1JW<0`oph3LXGk^CR6f`#iDXxZL90cdMCwN* zhd>LLZ9nP~4dwQupw|mUlWD1DS?Iw#oxXt}N?~j^=L0!;;*%vHN}w{OX^{~ejH__a z3-8XboK!+gD5W$%^6qEIu-=s4Jjqoq;t>K+U-84JP4X$X83Na#Fr7wB8{SE51rB~g zxfY`VqIEc^H=9OT{>4DT9C8f;HKLot|2#~GxWD!!WjCDl>~Ons-s&FJQHFd-;Mm#c z@A>}t86!=Ui&24@21K{hl?LDu9eU6aA96!Mlh-3)V5zY6B=w}}J2kg1kHW+&e|~PS z%seZ*dX>Wg!W~#Zp2iyt@V^)q{XqCM^U#HSd6ZO#`TM|x=ZG$>k6+Iv=PAE29A|>m znXD`-2MvYwLosNrK7`cD5rn;t<+R9 z_gRQ-NwL4%`(SW!hueeNl80}@9&b*6i0Iwa95WM-ZTGO$YR_?sxi;rA;ktOM{<%-~ ztrl{u-63p+TUGdntK{yJ8COXzj&7WL?CWYV>y)Xpx)er#w#U*n<>rfanObi=mb2F+ zW-Jr<6+6b`#2;!dBr8nKxL*1?7x(F=**@Nfu49K@NR0dE?t9h0`S)^cyq@7%zwrMI zom11kc&t_5Iro0;e#Lc+!;L7j-=8mdNj?g|G@TS-H+Wsyb7_8Z-Z7vlYVdtn#{ zi?UPA2@9<=Q2a`hLh)Viy5HYEe18TMJiTR7xBnwFEz|gR=sykPB3Ep$&s}z-(4j)f zc|zcB^lOO+gz;O8iL>Ew?>Fybs^|q?-+Q`OCt)?kY^IIo?_6|QAXcMHlJWcMCAP|hW4wm9Y@ahhgz5iU+FCXYH z7Ur>HTS%7tmXl`u*Pf@_LO>PKf6~pvTt8Kd>$yu6rcQ~@hq!su1j2n;A#%{L-H{(d zDHootO_g=fP4)>$7LUeTN*5xp*PsK$oQDUM20XHTvJR1(wtfI~FMpH^Sttj1)8G>m zes0*8zkhU4DP)Ou+(k~Jsg{EhYthO!t9^;nQOn}<%)RX^;*0UEH8*hh1oDjZ$J{st zHjv^G?T1wKRhUf?q2yB$m zu*9V~A6f+w9;6~*VG>ulN42nHuG-o4!+x@bkH>>}4Y~H*jEE33&Kbm?e{ZHq!~tKq z1Pk-VD(Y6hqfMbr6TcKPAl3i@PY(dN8qSjSok*)?#1wy4%ThSIW5!1-7ip#vkwX=k z%H=OXkJTo0C$)J!iGwK_g-MW40D-4HI;FdCqOmjNdeS47L@1RQV3ct(M=DluaBt0? zj+xw$(Yf^Hm%s@QT^!&(1gr{V0?ZLr=yN8J6iMZ5m-A!1qiBY>v7V($WNYScTTo$i zAv7Sb%jF7c@CH-{=6(nYKB>zR_X(#FPP5X2Pv1J82IMyA0SaImdnHgqJp6AQlS)QM zae+!3;+rOtb}s%&ZblZT2kMJjOXIwXm^J}eiTvZoY-+3ZHiI3%>Q?%FZ-NG!>CHdp zdvQ8Qoc(JBUfE?A;q>D!iZY;AzgYJsT^4&m_{CWdawc>Ggfu+GP{m|s19}c;c}=D& zIpc4WAQbT{LsmyNK-bR>oX6-g0dn>Qv}Voq2qRj=z&o%hb+u&<_|PvqfN%KeV_Upw>x8HJI)fsy=% z7tQZFf84xw22InrtRwq$#2iq(IQJmL@3FsvEw*(GAUF|J7S2x$O3(^yE*clCXuw zTQR2spljpr-dr49#^V9VP0RpVdw(OY7?_JfT=#qS^_cMof#DH%KZs2;e;9<> z`O@ShF5R&-`%+cBV0%liIjT26CHeGo1MtJwMypQKzh3>8HvssH5+0}B%FRAD+w?&_ z?xX>*X0@GrzJP}%)x14v{pLWU=u>7hFswL@_#7m+*uiy@E-|5ILBrCTY4W7E5dPo7AZZf9TkyDTFe|I)s6hhpFJL-b7i zNJQyw$;n8(-5fkXm$n1GIN z90)fD9tjj@0{Ia@umw;u5~R!oO$dU379jTsD4s&bQy^+N-_&}AZ7cL!n<18?!W<%N z(}cZJ#xNfuuy71r38dqA`>i0s;xd#)dSp7>o)LQRk;P{(! zcsd;pLuXJKG`{ZZ0)a%qP*c!f0BjfWi-JE~jQ^yvP&K1KJV5Y4PPuiC8O4mRk%$su zKt~_xpxbNn!xAvi zf7W7N)Py`N4pFVcAaLk&~n-2W!daB27UtcoB%k=R6JPQQ>dng5R8^$TuO9IJkhX zfLaBT$h2^9((tXa_=}Ti7zfrIrinO_>RXTjF+S5M<@}aciP7k^TzzmkWT{mvbV*U& z7lM&N@q^Uew~nWdX*!x7`JSwkn*vooH!~1LHuJW*i}G;A-oTmdOSBV z^ccCZR!yCoNN@}CU;^J8iCAOnhPG)Y3!PAxLHIt`nG+xpT8YjGNQySsRNsl9wiA3V zeB&%VNw$8>w)BTlVeJ;}H5`IN_md;F3o7J8LT~D>w3?mUMMMjM-!qB#k)~ZbBuO^> zp94|C7ZDmjxEk$4nbh5kR(q)(GOWFKGN0?Mv&{W55Jm{%GQkX+6ufLlav4Jn)|r{K z!Wx|gQldy#V~TBi;p57J{ZT&oE!q|cm<$3?wY?$Q8><6`^xmbaZR#7INLu9p|@ zVlRR76+5r)lY7Q%zyTR2r+3S_qg`9V7s}AKkohF?tW~Sqm0P_RNBVSnVu~5^$(hR; zrMGV_^21t7WUCOe;G^c~-~iUCMR(@X+>@ zsh(A?B4=h=_(wEEo)w&;C6kNr%5D>DGdUs#i2zenukJXWf~Y5NJIVEV-hUCeLQ_^C zMr#4&ZlvmbR^ZRqQ>tJZ#h64^xOsN8kWTLD2}Or*ih@HBaY88d&(3@{n+&O}?RNYL%)lU4> zk4qwq2=xl+?b`tokQlugzJ|^-GY`F9xGDd8Xr#anzv*_4DiVOVr{Y4KV6@N5S<~go$V}nWKUxLb+%Dx3lqEhP;4!jxK<($#VFVp4KMOVGrW_n? z$gy(ZEIbwUy{{j7$=+}t!4x=gK zq^_~fhkU18l0$PePzss_(jJM)T#%}oO_A*M`HXgu7)V{t%j19K$YX!CEcNP9d-ZsP z32z=XbN|R0En10Vgajj45_hU$T+Z9zwmL3BBp>Dv3{j5KkV}7VKcz-)aTs;3MPP%w)?MC3ie-Ii~-fmT_$ZOBhBk z@0vC0xsA^V);Ah7*hZaIG~GHM9Dm1*(TZ$hp0W@tSeOvMsxRL}D7tpx_FKc8<=sk` ztsw60s1-`g@=q0oE<*pi$e*(pj~v+hYpH5slscvbSEs}Y7tSh-!4YUTVe#8*yGOon zl|LA-4F7%is1Rf<5l+7T>9qKCqN; z%@&!`v?z!9#NQ_CSDnd)QYl8~RR35XPk4!S(|_Nahnfn9bdx z+hjp$BH-+TDEfjIY<=>e?QG-V)~Jps0*USXaRfN4M`mrx-U$~HM6s0z6Uu`YXekVp1|`dL!9FSY-{ z+bZBRyfCKFZl>9#CXuPGmtLfY35W|5QlXLOt{@fZB7qi>buY$1YI+pc2{{>pfEn`a z@}-_XOynB7K`6$BaH;#N*tJWMosQ>qp6>`gyX$soppE1O!eaY4D+)0|M9aAI^>tlA zK@WhK-rQ3^H8Q_(ukETYw;~f-Tnxu9NH`%*1sEUMd2qyqly#AGl7-#&f8)IKZ5mBpC%?s;GDTqoBYkT`Am<%vx{|;9m!7?| zz@3g-cl;arPHI(=lVF#HN^ICwEG+q>*XMS#jAGkA+VC&5kTXKCm%{(>LGS9i5w?J4~IrLbi+{t^NAw<@6##g!S*_bN6CM!A{OOmgKA+Q$e+f=pbvIpW`fpwE_!>F!>rd~3 zuLAS8YwGnLc-`M!DXz3jIumJT=JT5(Pw^6qt%vR8B|?#o(`I$)=EPI(%&2cI4*5qG1ht;6 zh%BtM&F{E>T4fzyu{d${d8z-<(+w}|M#mfWW2g0#S9Q8CNol2>VL$)5tQek^5>$^a ziyHL#RVtd<{*8S^ z!e5y7y`fxro1$aaw5wm;lFHojcb%HwrW9Nw45 zH3!Y?iEk_L7t#+aQZwj|28roY%&Em%!^0DXzFSGLy^ZO7JeK5-9;`>7h+-NEDZx0z zK(n#0oaZ98WuVTt$y&{CFw6naFQeY>w6~}8HJ=f5X+T${b#t!A?)-oJ#~y7hioDoA zelEIS0>O{D97a3Kla6>}?8(Yec?`;#v6n&BfRZ)v%TSD}hoY!ZME0~`)iQY&OH?2}z>JtW@ zzJD!5?vBi?`C!%(05(h+XIo!ht(0&Qdzg;3*uK_oft0&d{u190k9M{+jGm-%b&opw z=jpi(1>8J&JUBnf`sCx>Xrc7ILEZ!7PJoDQm>5dHkG4jHg;9u#Hn!==KEAMa=Ga~A zDPP;1lPO9!d5?tw4ncDnhfZ|?wMa7WWsM;Z__45SxMT%A90|4&3|TyjRZjBD)2Ru_ z5|vyuMAZs-P=@g+Vc#r8-OB$1ff76Ftk7&qVXbtW(YVrmVaEYkqg2KrycI4db!*U% z>ul>Qjn|F&FQhtwVi9WFgRl{v?P=azy)DilPeb&l&mbg~0Tj7x=Lz+WoqNvc3JZ&z z;qzl|D|m(#w*b-6=W@8tm=Fie;mJ;<6mwKhe7S5aNH>bv4;qPCp&&Bo)g?5F0=y}A zM0xgdvN;)UC+SJ(!SCJ^f;E}&U3Yt5E;1~fIWEQL&&t;_^7$p_uYjL;4Zn}ytrvf? zQE8=`HG=02zLYKx)KQ9%uZI+}O@^HWinHJAX6lZvD{Blz@n&dD&b^)!*b+;{ciV1< zqx(G^N@fITo3vSh9R5i*wPA$w5PYs*{ioF{vlddQ-wEvYK#|Mks6h#xiR~9M4?@fr z2lFjko@4ms3@v;&cB;7Q`Oe5bt~+7##C6!`#+CgNL$7~fDBGi;j_Ie&;%FHIW}jC? z3C`(}1oD`wM2>oni8yusEQv4d?*U&_BDWqOJwv!3O-onY6fNusdwdE9mxJ}|#tujes8@GdQhHop2`7K%20<1nw2}Ftl z8UPj=LJgp&awD_(z!9k1#qu;TPaw@HP^I^LUJh6J6B-|JS6V=HOOxA_1b3TAzhjQj z{C$eT0RisD3u@Ovm3>kqkp+t zVn&k=YH=sLA)as-+T;scd=Niz$-La7_KPkp!z-h{%!jRH5e?(`7oAdIZoPkaUDA>;qHgd%GeZ{HC16Xxz~2;Dczda5xDq?Hs?ctSk} z24BgcXK4`xmT;3w5D(6`&c;{8S<<(>2Gd&yiCqVj>c41}ymp+;bX&35Lm&F3>?o@|6aAbz|v-@qvMeDPDXMTqJX&9qZ(0mmC-ekBLKZx+8TIabdRQcig;WcwN* zdAvQ{D$LKn+#pu7MsN?Y>D z0%eM?m4gI`!WVPs0Bj?dI4=vQOG4sL`PT*mCdy%U#X)jC`5nEQ-0CwQFq9;h?p=yAdS!CX-uj0=*Ze54Pq zp$Zi6n`yVxxe?=oTjlCu@-&hO)sFMhikO$d-nooP{YnKF!H*A@nVApU0jWr z^X8;^7-+_eBpQ_g5SHDBA}^DAut=XWq1pTg$8IwIHBQA2sOC7G2iNKW!EDy71dEhd z{v?Ul(rZ`J7bIqa=+=m$+qbK{ziX0H_O_+hVM|*`zaC(EAP$QeO@0!`3>U?A>KCwXg}1Go;nl!$U2uR-#an~B7M6a92XDnQBr z`g88+a5Dt&O+@r(P@F3Wrp?<#;mR7d6Da3ucCz?v3VwqJ=h7{lDZoyMatfYH&H*;a z(t}nJB(-35tVDrP?ni8pE`T7BYo*Ip_QVl9@$Oz#JXH=L)m6K{z1%to!orU2r3t`c zzL)Z&B)8F|7HG2e5L}m<9Jc5s#{?Gd8r|nc&AMZnm{*iOUm1)wISdu+rzEa+S`Ozx zK^2ETO_&bN5IA~e!9wk$JhyJSVKH4Lnhgphg2BG&>4gz@og?^V;=csMAI7Zt(&JzB zB}iz6n~!0OYQpw^#79(!9*A(l8-60?m}2L*4Ue&)emNjhz3MV_dBCbh$vf+HKLqHnJEjz}58#&f)~Q3Iu{i9o2S@f zM3`H)MXSG{gXk7!OoRfRtb^m8plQd9@{RZ#1w%p){RSyC8DyJ~LMq{erTP8Hpt1?M zBBFM#BWQW`!u?q9OQv9jDp(+%ho2?=-!!k9oO~18L*iYow0K@J`&bY;Pr^5^iI&&k z7hI4Ej1;>dvB=3r5o4AtF=8>-r+k6yXnz4bcVFbSqO>b@tr&{cbsz zIOW9<^4&C&&jE-dC~ZTp@KJz79RzWL(ok2FC4)dQB`p>~^oqiXpM}@!3h!Gg|C_qI z5bc6dj4rJ3B`#wpYn6BCQLB)Xt)FF14I|%i~O8!Rl9ab0K z`5ly#--luyYXlOi-AQ*sjmi<0Ir5%W0+#pBVQTJJ2?OJG&=+w@A zx>j%B)v$AL&#Sf0fueG@RVa8ITA@vE}W^$q@*2k%svsbfuoM>7_RswWee!`94c zYhm%|vY)4z4#?&(BVozccL!7|{)LE2OEmrTZ2aw6^SZtss#?4Bs*vBNP3TYawr2}p z=KYz2R!Oh6i@+9=S3D{cJN3Sq*M=EgU!QN--0dkcaZpy$)lTEBbylry%{cjOozt$~ z-SMldqj0_BnrEHUpSH6{AB@*GyEn9E9F#w*Z}SL!XeZMi^EK4;64w0ny{UvYYrZze zuK-!@PMi9UnOAM^GCD7JHzhYP)4N+`Tk1_-Jq+(|+u~(Lg+3mte3TQ~Vb}dA@$19e zUt3~TyEXzkpJ*ZbFs-#-2Eq`Upe*G|#9 zU0pAk<)J;=K;+}1vfI2p;_*GxI$dK8#?`MSUdo2ge7N>JQ^;1f2OcH*@wM7p)u$gm z_$*6wjb}c6ZSo|j+vn>mpM|4cUsRu|Ec)!KcCKYUb7*~9;rVp*&(k9k&-PVW0^^)# zV7SolOqN~iGw3jje}g3m?_Ivj5;}(E!}f}0^@<;^v*8)S8@(THBC%?Ha<+X6VSQ77 zdX+asL@)QLZ}e%x`_YYkIz1w4*nUD*zhPtl37dXnHDUdp-XGolWZMC=EY$I=0U_W3 z=2+9L|A0OGx#PztR<_T%TL#3#+B;Q+>%Ts6+IW5j+wZD2=!ficz%~!pKj+CD6n*_% zi*GOj{sMb!FedEz*<&mnoD>>xqb;N5%GdVCUk6M6yig3|siE)+IEyGyhHCHuQ5!>V zZC>OaL%44=rct2$+T4i%R7x0c;Y8@OyKOg*J}jz7no)QP0K)vBJ6PXWE)^WE)Q>RF zheO$adkR=qxz^wqVwr_INS8I#{dcJMBQsC!WxiUSE`=wG4lJOUOGinj_1wZ%aJjLR zbn)pHuN%TVL5URJG-g4WKTjau^3B)_3#3gV;xvi^3`V@>58}-&LQP;tQe}X#4nv7} zFw2np_b{@6X2|UXNu%&)M~eGWcvx6ehV5%RnYS=w6f~SCoBguScI>k4a7@^6_Bwah zFfuR_w)gJkZkAahk^AqfH+M516}*Qf=DaRoOFvahn=N{%m1Gu3;c3h?)7g4$Fb0rU z9}mif4u_2d1Bzwl-UhlzJ}rjIQMgRQM+N>Nam)#au?YqKsTeAUHxLhYV{^NEkDVzQ z6w4kEZ@MRkpE~mCt*qqulomLR!js0rIz1UG+5i-X@fK_qx<$TP|TjZAByz9)I$y%JrY_!DWPESR_io$}S z;iK7XF$MN?#t7OeoJVdHHrj{`+iaJR zn1~oFoSUy9a-;rDQ2q`2WsjXd_AGXEDkgdq_wQ|0C1(~_{$6r=K5WJ2JWi?vnl4HxT%rT6Wk-nl7H$W zT8kp*fM6dseMpU?a+OV*;AQZ!*N-sv9sB~0^df&QA~?YZhpY3D|`uIJ#y zMsfGDg)1g&VV-MZ)pG{TFGliK9UGVE(ZU%Sp~~n9uR!^8TMMue?6=`*zv!2e7hVQC z&BC&QHT0@@H2ABce-f|1T8 zHN2g*BJ!(q%+=)F&?^gsuv~&=ZvSPSx744b$^nydmCt2cW;=Fo{+T|w@KWj1G@J^a zH(L--Tf&UK5TQ-Wxy@e#j|3%dm`6nvEv<%~m9aUuaO@z)Vi8}r064cmXF5w3{fix0 z{^0ivpiCS4^mu)^crFY(Izm}b*Bj2%>&sFoj$ka|nZrjEFeh}EGlmEMEl>SSnv&@n zNk02j|KCgBeW20uvFqi}vD$7kF}yZ`Y0i*K?2O?_0@ z5G8I%$9z2eSJ!K6KILp8XLa_#=$7Q(4V~OqzbapukG|5&{rKVR(BVaV*o8Sf^R;N% z&KGm%cb(C?7{*7XiAA=^SFfzq1pd1)-7nMlZ=XKS{B!969PI_|J%!=T;#(%Z-rm|+ zBn*_twUsL-5I+EE1meqhsinm|79dc|<{k?Mg7U23;ERxm1@FWSx#iEtKdyLV=f;v6 zQpGm@Yy6fU^YK9WhCF>X>^k)FPHYpNG&L&z_uL23*m)t$FZ0{ao#=>c!_68Z>$=6v zSJb<`W7`2Ao{k7Us(XItzkPG};&0o-zj79beQ(T-PHaYQ4n!a7jU79YZ}D-KiqSp@ zn!PieNCa6EClbct1~i)jnK?r;c(`(^)DZeJ^5a6sSnR)v_={t$BlzqlG(`lRP_yIx zd5RB&p=+|eiE}i9h^(lJ8p<-Q(u#|bW4EYKs-Z09Y%EEG?ouu8A!}HiFi@$fEuvEV zc8*s~u}DOP71&uW!!2seJ{P2Dh+I&Ds16e))n0MSF8txlN7%n|xn|pr?R-l(2DZo~ zJCO>*RHwwPBv^AMT?IGFtoC<(t&>Q*VMq=z4JY56KwXM6$dLC-Qk^h4mp!}{j7WQG zX%JTI^HwNS*5gQ4^y~R&UyhAeT3=KPc)lGmed};j*jZEliMf{0v6_Gv-=gO4pWJ-C z@Zx*Sk|6zsnp@}BxV2kyhLiE$O7a#}`M$!zv3-h;7aENK;@jgKK%uUWu-OieaN%-| z6H|;)88@&+Xx>kKNnjj8-ODjtpdBA|aGdsNQbe$h?_&EVabk5N4QQfn3C`dZ@56(u zyxZb^2kcevOs6&1HyKw4cPjlM$F#oh`;w-c>1j5>l<~w5X}yuvSmE9C1hrJ)bSt~F zSs3@G2i*A}q%zC&DpI{H(ld^oq4OuVRYvxcxZNB5_`Q5fmw8N6;aazLt4_Yb7bn9h z&je?q7pN#>>eH$p$ZG04>0 zpQBuq5)}8S{YMbj;4#iW`}Wz6;C<4szXXTahaCywRqp%QW?12C5?UNwbSjK%c=u;m zX~OFZ!B8eKyf6HKNAgwM;~9by4c^y864nj#pfrO+C^0=8Wu# z<_R6v#ajWy*OBOkg;yIyVig??=`NB}Mqo>r>L$<2uim8aQclI}jQ;xP*Vc&K|7YvP zV;H^-Q8a$p0M(qbdZFLoI7`IniZ@_w*F^x^f;+1ADMFf>Opq89||#=VYS!y;x!u%5=wqV!?t{p1rZ zPs{i9bW8si+bjJ&GHt)Nl~j%@8NN(M5(kvBMh+q=@NzY~s?XCZ9i3chf(Ft|g93k- zENoqjkQne7fq2HIDP9MF-zp8EiYK&%*h@?^JD?4f$MT~e2Wxrrm!{iuUYIaob!o-; zBsx{7fQJ5~oQ=FNA*`EH1AqK`Siu*FL-)jBQPYY$V)7M;VB&SjZU#M#yUgk+py6&F z$R*XnuSjn#!OVyi6yI?c=G<$jyrDCAcgb7r+hDqi0r;(1Fq5*~g}YK*9zM+JTjd_Q zczW9B=WxHwwlm)##+&j$wi%#BtUOmHVB(}oC`PoUyjnU7N8JJ$wE>h%hB=blyt`}R zEKaQ(P|T=8fN+{Lxb=Pp6wPCKTpCvd*H$;T0iwcQkP&thE`Lu2X=x-MmOjSwD#VgAGX{`1~SIG zOKw1wJ$Rd@A(GOK@G2UBT9K7-6qYoJM5XwC(SXL^$!43_o1g?ca$|eBO#UZy;$wAtfcMOVgH|jJoumwipx|OoT zVJ%&lLwS~2G_lmuQ=t%}BmYT-lc4lSfs_Y74dc6ICo;zuL3J>Q$3MZ+3he?sT%XF> zg}~F!9(9i4S^pOu4PqSz;^bDIxag-{tA5t)PTIoVH07svGyG5`6FD-aEE%s@hD>S; z(z&fm*#Or|^rc(vlxwhLrigup!-v_b$EzT_08!G9OrX=;x4MUOw@In=J8nx-6{5wK zdoxJF>!i!~#-hmDHguQ@m)a`Ihv;!yIQ`y4RM%X(gRuweOi+k)0+-P_Y5eGrpib$1`Cc)0xgFJ z^xBB4G6YuS&G8--L=NUg&N+_rqvt>e%MiHtUa|QXX&baM?Q=urF=_yFf3)*FCL?c znw;-dBF73sjx%A8<^sT8DcMq&`H_hgABeWhEOBD1fs_U-<|`BwJnn}T;F(b)e6y@@ zYDWaFFPJ!<>2>C=LDhj5#457|rE$hxff>9<^&=x-izyz)JNdkAiKVp765SzIwIHQF z`Hwm+v*KF#hU3p)IvOZXodI<4P4s|i=br+z=b$3PeD2h3k%IWR*igrC9<;;blIz}3 z;f8;+58Sn$&j#{atN(%gO=;qeuZD{UJ0V=|vpBI}$eyJW8F2?_V%FD44XR6BZYop2 zFOA>(i9{6C>(AMVt|5hn$vad`|I-VCohj~%CFv)nd-;61Dl}TS!+9)X zN8pL_L84xm{~vP@LOiFS?s-9ke8pGSA+byAsBo1D)!L(&JAgUqSYY$1J^|?5JB9`a z$i>)i!)edMkaLD*(h=5sR;mytKU|T;JTO&^m6!!N1Tv)U=&BjEV2(RfNGEdTV2yRx zrOaHR5~bfjv(Fe0Kzo`*07f?4zYdme&9b-ZJwXR*b9DM0Zs0nYu-InLRC)iQyVx%I zU`G4-Jk%hgYNUcmZ)SLfLq#J21NjHy?^NL4r#+N|UEI29&9BT^=SrsD@%RESIiMzu zW7CVP(%`y6I2f`=Z46MXsKx9r(c==+0&v2F0uFtg<)OirnIb>-W<%}}G~V6Y9E8iA zrUeZC&5mtE19Mw&gHu(3 zlVR1t^@fARX&%KaDMw2q|8DCaByNS_=b#E1Z%8oBI$h@RkUHry+;h(WgCvG!3(I4`+<6JS%SH~4tuF8v+$?xV z|9sOOe`CPO_*fSljZ2qy03Rb}MC)f@I_x#HYSiUS@8s(ToN=B*0RsI?#Zz_}iZ&Xj z!1!?nj0ni^&dR-`sx<(NE^=kkhFDMoaZj9Nn5!i_ql<5eKdp0(zu7j2_7r6{e^{ z!xS1 z$UjuLwQ%K!6_wuL;0gh92#&nM$_vr$1Wt^ShmI>LA&-kbeU2E$5AJgIq~oF*O3&baTsp+-wh|Q?`-IQH;4DkPHzo$*bUScXxaBG21(+58;V_5qDGlG|Ja#9; zumf@(ce%#U`5}1gReT%L4L|N&5C^2=*h+Kh_JlHzVJq143FYl^w|NATm^Nc*?KEvw zj&?@wG`9@3RB*_ksmQ7Q))(f6r~OMu9_1kp+^$6s8Kwt&&gx^SbpYWYkRF^Vg45D7 zR>ku8dk}UYFK4EmFF;Kr&2i;=im5HvuI2`~(MyBr z z{5OFak%AYgyNNihd2qX4gx36E2$TA^-XPQt7RlhFS^}@|1uEG$01ndL&L?Hky_!Kb z;m}``AWy&jPC7L*xNONQASA%KM1%c*WW&ZXY(@v5BQzV%xC)lWK@Fd$S?>^P?YCxO z<7|%#pbAc3XlX95!n?eAf{SB&j(7YCg6aO45H*BX>9R1!`_Y8|6iQjU=vA2t;9QW2 zc`K)xxxSpF;PY|w_N{y{bGx$*VzhUUAc#FHE9OUZog^X zpbd?^;eYk|MU=hnGln>A9+6#o^bZcvQ90kDCA5@Q)!M>-@K7aD?vjp=dnx#s_aPw- z2--?}_y%yKkg=`>vRAP}5^l>Bv+y9(hXS_4j3jT^%=yED=IZn=eomse)HF0NyQ&s( z91y&%AuJ0VniMEaRGN!rci5Qm*nw;Xb%kaQgl^x#8LXbq= zMPJKzcWzTt6!X2WCT|b#HhbRtn&_8${R1(r(Xe0~w4tYL?K#vGm;FFo;p779`odig zVg{s3>%|?A^ZH$Nh4SfBcx>v}`%67HXt2+J6vwtyPL*=B%izBY#|h=is(x}|8ttb| z)6J|Exy0sUvbP{!!1K3ni8!bt9d)wS>xGmn)8xGYJ7=5W+Rd9fC3c!Be!f-Zs%}Wa zSircuP%&xIx89_g?yke4S1jWuUj`3_EH8)1*50OjvxDRJM;(VgDq#h{O-koi?Yu-@ zet4AuT6Eb5c$tXxynXpl)=k?ko2?Pf>RJ}mJFND}!7P9dGCVA#&t~U<3nUM4IG$-F z>h{V`GQ{&zR$@YNgQQsl$FtQx^e&Nl8f|PQ*--%%ti|s=6DjN@|1UxKkkLaGi zKh1kvU^od+UB-rx@{dJSi9jz~FysPt-IgvYY8zu;Z?&#R3OX%LC``tBa0!UsCdWzlnKBM$2>Wv?yn zHVFQ4yUaIcI41_x_N<0)T#91^jTV%BJMqM;B&A%cc6DP^A*%LS_+(Mhpi9*4k`sJj z;c(!)DOl88n8ZYG)Qf*5tVJ$bxbnqo)XcxA8}tvejRiKhJ}jC?uep4@6@h*A8nJZl z<5lsGy@-pi8>8Ppj@~GjTVIUk=0#7cjc@FT#(YwU`P?Y=(R?%d)5qRtA9C&%%)8_Q z2zV#mm|wdji6WWp(alJ=O_$xx(fcs~u~^`qtrHV5;3kQGYOzzC7-&qa(D|)glUT&% zd`M>OI4u@A7Ax{Hc3(-Xm~^i2{ynJuSH$1MN?62+?!-!dzks%l%hHIGz8EKS@sngz z+(P&#naoZ6%Qyv#Xt|xZmD&x3WRah0BDg*ADu?1fz~a>|ir|mLYg~-iy!b(_DgGJu zv*uX5?#uZ1cR#D0kJl4RAni%0{1mSyl%RhoVc*d&98vPxu;|0U>L{9w6L!R6X<%_9&hZerg*3xE9~Hr8RdnkysQ zyltnRKUR@@#^(Zz&(PE@rdphAFxi&vPpDQb9=e|sosdubA(qD3lWvScG&9gYu@)Ne zaKyI5uH2&nJfLu)k)}mKpvEfl$|}IX`zJ?nN&h19zT2EUAtZD7Xq?wxS&OAa(FJ6( z5AGPLu8B|*kSy&kmgAZ!?xB&i_uw}!?)xY~>;#7 z(kzS9Htdkc&ZBKUeLpUiQg^S2xwFL*l3homZrKtM-l^x0agLI}Xk3@t@l4an&h^~9Lq9S; zrM(-tCteJ$oP+MtO=R__Un)arw4$&v3Wv`1b=9Y9P>VR zVJVqACq`~LSJjlFO}JdR6N}V%D|}@xE3W_F!Ow(|5A9nZ}Og9}N z6K`Yf=+f;ie1Ce`_Lk#SrFMvZ?F~bjmJAh>8O4AMU=vP@F zX1d>Pca6I-e<#B8_s(EP%W8L{Xu#{n`n!Vnums|rqMVa#@SJFc5ssey(|^@k>{m~$ ztFoYCtollup)G4$+@aOT4*ZlE^AUQeO7!_aq1jrF!{kxV*t`IkPC>+|PM$A-XFoMR_>*mgdX@UptTaH6amvPz7&~wc(_A;;WHRXnjrdTYy)njG^W23*6Ad^`eiU zGkCXjH)WSi6M%N&LFd!Q&InDkMDorRC62dli#%Ao@nzDl>CyKUB<{xV&o7$(`{R3M zFQeIkkZ;AB4aG#c+q)72+$nfcjJwseNA5yQV zk6%xpdVa&5J2i$%%_I9)OIt^Q|6a6?S%5G2?3z`j0^;ExPLhsF9yxPl3UTdBoB!fL zk#<+lorHO*A=^L^H^hFgTPJ7rBTT3Wa;S6L^AoKLNslPq^7rQdiGE0;MeL}bTuchC z+yC-BSfOJnb0nZ+Idi}F_oWe)*ef7P|u-E(i}d9%)Dz@oa(c(ziy5}hk~He&3NxV(6fm4AEBGF%af zDrO0v*PP6TE{ee+59hk=i6mh_d5G{sT!xxI9~I^V)&#T4w=v3OkXB55{|kbUW??6a zx?|-M6I-4h7@LOH+0CPh0slU`v*@)S6=#*Z_Ue$O#s5%G`-Lylx8FR%wvo@Av=_iq z)&b`0)Z`<^Fx3#Hv|zmQu2iv`G!MvAHTtCJjkO1_5x9#B&`i^wqq^fXE1`l3@l)P> z86gRl9OJ#>UOPd6FWRcaTY%Gxg<~pGP%=0+w1BZ9{f=s_7BmJt%T^*tzU{YBV8ezr zSc5vvNYgnexSN-TWU-k_#A-UKHp!Qzjnwk`jos6u>X>(0L)6l;T>^75&TN zzbbU^eaVoZIi!=q8N$)7R*$wSB^3*(x@||Kk$s}pzUi=E zSlpUhr5lEW8SMc%ATqQIl1Uj-3i?o(5lyUnTwT9#m$9C>U9ET$?sWQ;V*qtuUDg@!Y^&3bY)OC+8L(OZfE`_RBRHejN2{SZ`SiAj>Cb;;E-(nWdU zBo9K*nQ{ok2EddNTjBUlD@o}3lkrlF46zL;xO#o3_g6+OXrX-xmh#FO>}1UDG$piN zc_fgp++Uq}MgU3DI40mR*n4a9^+IC#qygHcY1VY9C?V~*k9Ph++{wKctkdA4pOIAK z73mXZ15$}JwnFFO-53YvCL?UC;6iJoCX(Unbu1}E!o%vX^?MY02)T6Q!eSXxYA*mzrL5g(DV>xw z;UT0Ggf1rbDW!ntx;m#oA5IQnKfa%~wBOgO)rdN*_>>`T^QLYB0fZNA!Aky2>QMpR z-j=aE9V;MM5q^{^9*Hs^R)uOV2_QS3TMN)g8pzoT_|LP0xgX{Rnp(1lAL#1Vo#w;a zz4hb_&@tps9Z3q#VZfgkiU?jLu2TfR6gH4Jw&Z1)#FCy>qi;&8aeiF=mdPE!DLy?t|s|Q|kBS>pS zXsA%bl1Qd#6ITSYGy8y6feIZESXQ}a5FSf{RkiY3UwjUjd?&UNIlMtp8M3+f=AH|# z^%~`ieiU5c*@-K2P|%A=(%&fchnmd^b}Ecx`MXu*MG`|kmlQi!a~s$mu(#^(JfQsd zpP*Z2y0oEzzN5vYsbtdLp|syh=EQDjybsy(p4_Dj2WXR_SXRIMoy5&E71{5dhX`T^ zFRL3_Y01_G^-g}ws9+=rt4Ba#uUJeXE*Pd7YuEZpi3{DszA2UmR>RUW+_sj_*bJtE zrCQ)=+?6w@_M@uuqcLcr<=QuM-ebq6pmP=6UF@$Y=bxerRr1BAO$xvq>r74uKoV@uf6=2=hnfWD-~ zJ}TA%T;4Aa@~^b3cw=$#L$?hcbA8Wq(EUf=)j|d%Vmh?p$etXCnt9qmbI5xX_#zqd z^fu3xu|RPmi{g%o%do8mt+KwlfZGCkx2{Y=W=U(59#5K0;*w?Yk>-OvnV&9a9kf~= z$yVCv($ko;)L5hp3zV)?w6I+YG%9$UKeP;b<=mx&XRA4Naw0#!>gNhe1 z)ZMn-XwI$jQ=M~|U6pI60K%9#GSTb(iYx=ah;9bf4)!uD@s|dBlS^Fld&x=6BVqCd zJO3Kk{U!j!DD*3b4$)eZP0MK#}H62{}MbY4lkFs zTBoSlthkr-V4b>_$ofGxw3w;!tN>x-4msGP#APLIgH}u! zq|QkN4eBqp03Xf*!@+y(_?;i}Udi`po_T@C$ORCq4JLarK=&zpu(PV-7?Exs&yz6C zy@2qy>l9#Uj0;f=d&nBB$IUNB?*v&_PlBxSd7RFEe zkCfKY`N&aWBzdC!5gf@VK-uw#u8R%a0)=L>9fRTSPA%Q-PI5i5BX%PbillY%qjuLs z=b1O487+fD{y17$IwLUax$v@BsdY(yJMUlVb^B75^+Bt#K|Y+p=jw>dG&7Ev_9!`l zSA6&cI-fo|;E~HfS-sxl9OkXSRtl%O4r8ZAm3@h1f)_V==UIIE`8l*^&(u8G5@~izGPlSIMgJIYI z@k_#99Y)d_Kiyq%YOjva*F>QOBk*UzlC2L-Cxn)00)?Go!O9|8{R_DvC z_AGVjvEd@)UAyBtS;%s|tGBTpb?0S?K+ljNvrRSsz{Jz$G*R9!7ml6#EPZ(rnx*%) z@cCMTC?`?2Zr%0RD!L5p$>&qJFQPo;3Vj9_F8pBkxKL&HpA9KL$d*D`av~QfA-*s) z{5pmE!--pS>B22jHng-W&h)sQHvq=IVb7(${96TGe>d@|&T}}wisJNZUEXTG?x>Y- zj)F~1mV*p{@zu&XobNx7l@xFmN3{B?&6;GUu z73tL(vEQ!nPtmFs&VYr~dlqX~URtbtr@f-`Zp9NdVeLGFf=e$<^%j&R7Yougv+Zk# zlguDdbGt$c>TOshy|LTwt+9pTY-952Pn>qxYR>r_STo?;m4s&u_n9LPz!ibQ)D1kk?g4iBax9 zdItg8+P8IJqGGdFBhTd#Q|z9}T<-Krj?Bi9lTLhCh3<3Eihj)p7?%&}9G-+n%wyeFO5t#*r9UL!jq|8C3Kb=|fe?@O)MAf_wDX((V5) zId?B2XTx~&D^OT=&wOg*RB_LezRsjW5~2aWAx6J5_|*m&ViuVkB(U-H*EdO+%(;+1~h$^g+%G>{h|Q>s@C*1TkFm7 zm=DJ{X=X7$sCL^ydJj`Kzvsfb!(zTS?)~*3<|rrTk3Rh8>2d~_Yz+O{cK z{mCPgw6haU8pX3@AielR2L`_1(%Z4D)2ekiU5YbUW!Im3{e2~aOl@4Hpr7rdB~U2x=ffwgT%Ux`x|#jw@D@6L`T z&&qnuC07TDdkKYmZd3f*R6`PF44}Z#&p*#4IK1>T?%yE#g-)XvWhPLLQ+HqEOI5(&9xeA9Lc;G>>pD}?YpBt*!y+F!pNuvggeUYp*vQ2}p6 z?zeNIQ-4B-6L_hospIJ-Z?ZDJ>r!NYH2h>d_KSa_z9Y`oQ6qhCj&lNbUy?UV5--$b zHGFK!@RD7kcg}$AOI!CJeMVoP{(gxrhU62~cfqA?>Z>QCkr{zGO^z>~?3j&RQa~1 zV05kLRhHaskYu<1>tSSeqV%tp-~E-!rbkbU3UJ(mt0STL&fVnbr?3WX zqYJNHMg~29-yPeYnKWF>{xqCDJc}0URJkyy0eCOeTA6f_AtNp6NIlFqE@~1Jf zBnaPAe-E8${O+aG_vbV}%+7`}__Tnpf9$lY9l-BTZ`T2Xxz67^J(kBhk9_Q$`h8TT z=aKfu3Zz*CuE}#8kg~qN_v)D???3N?&PZ4|&z1jq;^;DT)U37pOyJh(kyW#yC!Gt8 zoq(Oum1a@xYq$-R*oQ>f${@gIB4-lmBwkDpQh79ffIs@hY~+RCsQIC7Gssu(L%n5I zzZ1t8jIpG*)<5ma*J=(udkvlY?;^N@LZ?9f^8Ej8Ts*oxwsT$Y0hPV@A{_)gycgG9 zbm~mNFyLGf?4_LPj6~Gf3oiU^1G5+{e2W)&AC02)pk~HJUXAbFa1Ba)NdbsId$~qB z2*GHIONcxMM^0FpiT^HvN%~BLJGn^)h`&3L_rZfJZGX^;Bfj%y_2RDW4_Im?d)sZ` zbMMVl{rH&)`I*ZKCRRFy>*3_{iYEMRIgH7vvvmBVmqL$Hy60C9jj!tIs`SYu-g&hs zclC%tx1e+9$wrYg)=Af4B-BBhnl862YldEfDfYcvjdic6YEG-5(L`6i)akxH zNYNH1Y^uMaF~)+MDPAdQX{K=Gkl~oMC$84Qw?R98lGGEnVtHo$Avzy_AEAQ>E@_^~ zHM{?Ly1bu*HmOms4`&l*^&phzhVNhn0|ON*GX`(QcU^rlFb~@1OW_fq)5=M~PTetrM!Uh5eutFU&~O0FpjRgP)9X4X89I67ofYIQtWr0#Ug!N2ob_W%xbr@rx_JF+JfYh` zC-3>H^4(}FONfwEtjZ-^1U4Kg&s|^cO2?5hOg})n8BK^QRufFLv1esEOegBIm5>9i zhQqpZhwPH2Z~Y$L`vQ(88WkfT9_ zFQ?l;hm!n)e~>lOu_?tnWT=bu91T=_c#cyg0y*u@ifAi#0A2aXE?S^6h3QXV`sQF0h!u zE`vC8-HU37qME+Rgs72WjhBU$)n4jdPoMei;Y8gW)`O=}Y9!nrK6@U`7n%1wCVwl? z`>=VXbp}1Gm`>Kv@nyEfR&oN@W62=YgIGt3(IaICaaI#2>b* za2r4RBjtJiv7H%0+TWc$3?Oz1(4E$tA&+M2`cSd>X4d}oQ4b7qTo`+YpW z!wl}Ald3uk!M<*KtZjWo96XH_<_fy*DVChWQEi*;)pOG5LRBwy>&p|}Od^AYy#&$HVTc&c z!C~Q?mH}ruCRE*_Mo%m8pNx_0+Y!h z(A@_!OIS7O2Usl-CXZ|vz`&x7V<1`BVTj&-T&WX5NPGtFh)FA$+PQT*7l1MMJrNfgf1RoXRY{+kp&wEa5{`bVp0Vd6I7b&nkj7;N9)6Gkhph$=0o(tluOFL*)owl zb%yL62-u3-02=hBQu!I^Gh70d2EHN6(pOMod+cHPpmb(5l|ERjiFer5MxI6+{-HvU zyeE5p=6eQj2rj9YJx6Ogv_qX}@N9ZkzLbROQm=Tk%werFBVP5(kD|2VacuMjRdLz2 zDoI0zoySG0HGDSl@@Zoz1*_AOj?&tjmdy_2m!NgwmOB#1{oc|`TR@~M)9Tq3 z5Q|&q2|48#?vTZkxaqBU;9DUtW?#Dfdb=)5RmW=UxedEwsHJVP`%qRV4oUMQ=;Jxi zVRRGI|1M$Xi}Mlb7Wh~Oop9O}g5ip1n2bB(&hQvWF4N8=b_#f=YLKuF71uj$qIkG( zu<(-?dQm}kBFpP$4D-c$hR+7m_Ea~9NNW)Z51o{Y)uaN3($qo-efDqx%$*pJPv_U# zSnGUDX>P|2cxRb1OMH%X0+l|fn40MhfIe4Tl1((M|1AKp6HqD&>)f#YJ`5+gMDbXJ z7WDKp9>)63qcBqdL=EQv_V-<(->aId-=Pa!`N?~w7_W^%;(f!sW7-cX#B(^l=Kxu}O`p-De!1&ubL9$V8{3s$Hlph1_opKx)zUY>Kc0w2` z^8^J}(O(j;IXT#Uy0A;-LK&R*xlkYv5m}iL^6wxVIs5vRQWy~`gaV0Uh+z0ytT3YU z9^^DZ^5JtQaIbKP@KdJU)U{k*(aU+DEh&_&`eIH?BKYFOAlt3mpQmkoWjK~Lu}VM7GZNs zREp-;Wr`JnvEDy^9W7t~O=$%IBUYUk z>RD*SSNz7;n=Xkd!kU3?dxsL?2C3xVM!HJu2ri!YtH$a#_YknX3lxb2N7lnLD5CzF z@2*r!yKZ_LE}M+rAZ7ys)?C>m>I5C8QBZ=yYzJLdp!XjACU!qqu3Pxfd!)71DG}~x66`eeY zQvLIoEmZ%JXsR8bcycaw+@h{*%c zRpA#tzG_0l>p(4151l11c1g8UC2WAVhyv-a)mVdS!bhil{(Ok!Ypi{X^w>p00a~{D z6C6B-s3$2!Lvz<0kx_iVyUDUubv#Q#n4y!o%hKJuFHDAJK0ftr6rdiub54M7zBfi z_}Y*3AK%^3-cN(5F|ZH8Vt($rPd}FiVzd#HHQ|%$Z$9hBWg>I#=v~F^P0!Oh9lv$P z8jR65{(On}=Ciy+xMKdLJ2JO48`o*H-;eP8=c5EH#9JUHtkEu-+#*BB-}v%w1;tM zf`PSVXIQ8)V#?@pzR6SY{(K43Y7f(!9`vMqQ?YeolL6jw(6qgkaK}UGiicUhhgtd5 zfuF1LQ>_Qa@(;?{9DE^R{!`!FWX1Stf_ZO^#-N8q$&}gV7g-;W?q3h`NeS|Y1hUw+ z*F#Zc`6TTUubPEIqAcJS`m)RZSADJUp$B z6j=LBQ=PFkmEzU`1vV$9ZDO#t`weW86J<+?w&$^SX`XhO1y-k~?IfaXvOMiC?-bZy zZL_(Ebr93FFDr1UpLS^SBv*SnCY*3+nRfgS>(p&%c(1@|>Xu_K)_Ka)`6;%1Xxdq5 z-RYU9%bNn1_iaZPv4{SuyL>1(^n3bHi{T+~A?@4tA>@p!n4~TAup1DzUzZQH;X@sk z+yZDb+hB-FJH!*EO(MJ7@&V$Ko|cC_uf@4Jo-~h55F4c&KJpchqti2(hqDCni+3cv z_uVRuD`<$I;e3!xd zZ&rw1X*~RfEEcxUg2>0$(M5(UBu6Q@_(FPJC4NW}J+O>7mo#rDNWyly&b)i&!^{a3 zVTos>nen{jW;%g8Lne`FOl_amG@r7sM@)i_LO~M$@_Z+@eYJ}Y{`w-@!<4-Bu`!$v zvZ{k;18z~j`E)Jeoscg^D`mZdU~P;eX0xCMfU)nlP+b6|2A~!#HLgPl5r``~00M+q zGQ$*)XA?M7mTLbX4)G&Jw;zu-(R#QUTzTC^*mdLp3zn;bnZAARfDne?A~QN|9ilJZ#wv zAEk&l?w$h>w8MwRFGuwP1HJ7;>I7GF=#@l^t^2@+jVzPL^TH^;F8Phf1r_ zu|0xgkS=IAQ?7=2I4C*EPx)xn<)nNgpH@0HtU|i3QhIwxxJXehLm-|^7jvh}20l%6 zJMun}iSMYCT_Z@^&vD5}9K3!qkUKs7AW~y?baj9o<2Z zBa4EyC~|dl%*qMrhRgUN)id(6voD?kZGfTje0*p0d5_BTHwou5C~`LRZ`t2dRk~yp+JLxAG$% z;1vJ>*Hp;zE8pWN>>b~KrQcL&bkNu`F% z_+q+r1_e)ZC9BiBFWr^3N)qd2N;Uz{l9x_GyFdh)7lGe>v`sD@O_oljr)E^ju7qOW zNg@U)CJj;tlISuI97H>qYUpQ#;^nKm-qs;t!HT+dX=QyE1Mfi2-+RBLYM%n7Leih9 z+C>S128lF!5rh@-Yh+MO1>QkbG8}luop~jRDfg=aes1)Vs*g$0DFPg)E^2Ij_x@Fh zr^+P0jM*iaQ%TW%AOy8zr0~QxO`axtr_wVUfM7oh%aM8M@Z-pNnNoRzWNIZug@9@X z7eSTIsVtQ}rPbFhUlnE^uSX;>Q|vN}tHFFT+hu$_>Usbzc9mc{TB#kb7?{Px-)$G; zS2B7F58teuQ>lOq15f)2@E}*;Xw#cnvp}5U^)DasYfD+({A1#*0BPpQ!Ae=Jedcne z)*pq!1NbO@CGi*F^r5~yD79Yj?Z`+)eE{h6<_u7+^3WPh77vhs4N6j7BdlNHA2`&d z7nyq91GX*6hATD7SETlu*55PT?7IS6nE~?d6MF8Kv?j@}F?=XndzqHf#x>LBSdd9^{OKBvUR}do6lD zz>h9p?NSVAefm)F5ZH5df2txr93=7D7i7bXxmg*0-Y8u08~)Ny^Bbm(C55nG1ia}f zUi;{Oz&|EIr}+`h{MA%(|K$+KUCBBizl5$kEPGd*ejnK-6ZX@O4+Mt`E)PEka_C}! z%4l)__W=57%~Q4FR|&)y_vFb%$g8jeCHFpjJ?FpjpEEwP#H96!3^QiF6$&Z}0Cq*V zcDe1Gp>4|GXBh;ZfA2$|invm~H4rgMpNW>c5<$mk*k>K}FS=pWK}zfx`)2agD^2L0 z>{`ibJ_XnCh9mSn69J0#*lg$)pojqRQ6>y?Sv)ofvw+G;;GUZp=zmF+##(yqOX<#h1+o`Nu z^se`&NqeE_(|XN7`opQ5vi%AV3C(AGG0#*}UOf4`Z#W=vcyQi!-)Bx7%V&)KKOCKl zKa=nO$9FQrw&uJc=DZx%oJXq7D2W^sqUL-qr$j|NVM&@}BQa+RDJqhhL(T~yN}BVz zB%SNy=llB;?#F$&uKRVpU(YAPZAT^Y9$CyI9uqcR-GPN4A$K%S^og}Au!q;AsCf@50#zav5O+tp`Yn`m6o|Ug{cKORc;eiChXkk&RZbKr{fIYV z{T#)BF8H2aaDVP1HO0M5p#}mJvcce4Yz^*j=wU@joClgP<7BT9lNBplp_%xre%?E= z|E@Pm2LPrP+sArgYxoK_g8h9TfR=62=}ahhs_RMEiaKwhR&lL+ug0Q4A@OhjU@?I@ zxfpq7={QZ{*-Ifv9`-j@UabbUyOUii}b>1pZoGoX1YR825P?gPrTeCa6` zdmJLyxA4-y6J*wQ^YzZ1BX2&06-ky|M}RxY^}}(p1Hj7TRXMNe3Qo#^mt&X{{}eil zC1SmsFZ|y9IDHS@`A#=`ecT_B`V>|%qab>4LYndOWR83g-EA%!S^-q}U9hy%F62p< ze^xB5(=BwOO}@U!+xym^R;AIs)HWfXQM;pPzOwwl#YyMy`wI{Mu01IKU&be3xU7fr zziVyqColdqC}9;~F@kpKC!t&d3@#hMBZ;+i4re-4odVMbe;d{lRy>H_9txisl+th8k4ReMhPJ1%NPi&Vbr+v1NeXkal# z+ot-N4z{HBnStGj(QXb7g=jY51Q)z9^L6dx>zxD8^M-6or>hW|AORhwQ6*q7 zYnKE})DheaE9=oMu8ax7Z?}A}w>*=AO~%c#)pCPoui=oEGpRa{msPIIRN&^)49A1! zZV(r%N_Q^q|GqqTlf;mjOShB>p3kt>sGiT967`w7? zYtgQGf$NtWyqFi%2V2Y!d)%DI4er{vR1h;BT$Vxdk;O@%Vtk~7+OF8GXR;$W#Qx_|%DndM}Dju({-m9Oj zTCHh}?Fy-BTD-efCp5mgc0c<=-&%dAOlVjZU*q20`flU3^@c7jZQZ*A7NHxDCeqC| z9%s4U-gqKN7Q;Q6ms_oETCTYFDR<%V?WJ8%j`rtg2cCxRFRBhtCX2|p1+>A?RE?wP zvSR{^9TEK0qQ8hUXFBQM{sjYMi79Fp4%r)d%HuB9BAE>m0)co6Gg zgY7e27}$(B!Se=OH%W@|EEF1>f2N_K4nFoZkaRk1d)Qj@j!sv;a%8$ywp~=Z0yo(9 zTTp62M~~d)xaf3gdzq+oj6~x-E3NE}cKx8V?b*%Xv;i_k1CkZ{m}M0$W5Nna$u(hJ z*4F(gV96emdz0rLF=&)6?Tysk`ElZq#0D7NwAufvDFg_FX~@!m&$rIMDTy;Jm@Ymwp&r|SpYG<`%x~Bi>fX>DoNQH ztlW3=;?V75_N|v*UHtxo`A#1H-_Q9y>2U#L1(e&6ewH&xqP+CVBZEl@^_yS+s1iwO zniGxGEA60}R**5?*`<)s9%x@DnF#>QD$r0VL;{~3!3&dXjHhZlJZ8J_YK(w57SW+X zWN-lM@2oAW+N7Kwk{uzNg-#+?6esmI(PXB$$y2yekw{u;U{u7BccNr*yWLv$+f59V zFmod;tprl9EH+l~prdJ^e2>32OFUz_p|_?!NxhS=cDD`T0Xwgsz)dDzQf^S$t(3R- z9MJ+*yd>+)$%TURh3X?80oV-RtYIP3GBiN8aTY654TowK-w3e78sz{;Ue;tw?ILCw-7c!eGxsX3($PS60)gh zM@N(Zqb4XK0%ta0Xf_xuMpGFFfb0r?cyPLeUXj>3uw`nGg#nJaQQ7>~>I!1qv z)fJW1%2{zpZ>fx24qUgDgtA+}pi zZTG^0%1{E>inaFKP;Z%!EViDHt@8%Hrc=cY>S;R~CCym}A$(B#5bi|VBItZgG0+O! zX=vsOic-kd*V#b7mhuLo8r!8uk0;?%FNs=NOIGiqWNqIP2IW41N+iB@Eptfeax!#z z6>Yh*|3oJMTwe(Z+^$F0n|`xbH&=M0gJ2er?lN>ls+Mc(mee~rcq!Jk^I6(xy8skr znWcZt=xFaJlijq5FFy)Dj?}hSpCHR&B z!%Zi*p@MSrgD?Fawx2l{@m1dyb`%i1Giz$u42dvlQm>wO}86|w+s0i3$5F?mTs2yVA42wnPg?KSEE(INO ztSy+^p|C`1KQZA$u?qsfnnKr)8#^I;THiiWM?w3r&+(X*NU`E9wSJ)` zaexMVZ_G(V&~*Q66bBrsku?DQH3&&*OH*;<$xa24^h4dO&zJc?(OBVkim=CYvy&|) zLm0$e@sPnLsxNFI_dWBnqcZg8-sh@>DQ64k zBl4lV0Xgi`bvH@wb67=;mJQbg#Q{rZr$+#GX>PCYa0X=S21bsVCAl#t^bKztpTit{ zlDUtuk>&W~meB}6*JOu^PAE&8nyhtKdj01!ZO@hXRXfZ^Aq8z_kU~IJ-5}aa9x5Md zk2xNz@8w2DKBa!{1su!U_cIzotExHRYk+x>=MCNe##(zooWRT)g*%tFsRnJHY7$#l zIQB$VH5u5lhWs7%250H`XfrfVmf<1FHOp!Dfnr?ZE2+FbEbz(pOW4L z6UUxoil;waE)wxYhT|FftNg}NBJbq ziw2Ux$DSl+4JU#%klq}(t?sCH1F*n>f<_6e^1>yo=`vNmKq_3foXS~*>o=V6Z@9SO zn(%fBWUm&tqcg$4b1|%=m{}6C-Pd;3L8OHviikMe8I7Fe*t)0!uL}-OkzAXSF24tZ zM9UD##=>1z7*~SD;3nziNu{h|u^9(r2Mysfsz~-2=1o%YLZ(dUFaYId4F$^NcwbSD zLAt&S|@F$<4Z!hdAYkQJ4|OI$EbKv+pm!rwQ<>?AY$nc#5MG zFw4Y(EOkxoqT+;J0m?9XH%M2zs?c*Wt}4Y@5W1h6)`yPMtHL~;N#iO5eR?o&f-pNH z+^E~iH-NMox;;0}ZpGwypUqQ-$D7D?ljWA0(pH<&*I}x^M$$LqFam4LER6b=VD^Q3 z^LNwD@R78?J?YawZ-PuY5D~Ti+&Hj2j%YIn{tF{K$w6T&b!}=UD1kMQIFmycX9GoV&1-;_(}Cw zP5Xtv8drX~#m?iVN^l)V(wZ-ji?fNrL;LgFaBmg?q&H~uEQ5b-(lkBc2>>XK4DJLt z!DjR5dZKnf4CFi7nvZZrDOMe`y749dLGRwiNpuUz5?KuMXDOu>=M%TW*^zlL9|L0P z-r5xuZ(lx=&vh6{D_0c`rP`b4ViE*ix4rW`=z0Bgbff_)hJvkXmIdnxm5}7GE5onz zuvH@H1b*IHuLQEbAZ-|+9ufI)QX0AG)Z~rcb$k7+E^7KE^K?=H>@6f9fHESD!Qw@H zjKX5`-p)Mv56yceJ<#EEa$s>D$h(M~Q78+%V=uuJIf`M<>+KZJnWCxT>NFsh1V+x; zHqQYbX1U=7fakuz$9h8B!5X*n^4P@(D|?Hs3MrT_6#f-Ki`$@QNJUs1l`4_5>@Q`% z$mMAdZtqMAvt==Tb5d=}!eaoW+&9^yHpNeNQ6$&)26~`hf0cFhC^8?$s-@yw;xV`1 z>VbvAk^IB|fl2kZ^h2qp<19NQge<`V61Pt*5fBHJEz~Tr9@yOnSV?JBrbA$9{;u+& z<#D1Omgfor6^mUappK7P+FPPhVx*1V-LbH-!9?9X0kK-ZTKzK>1`P`jppczdrIvc( zY68M=9%V&9SZ5>^m>n-k1(wqg=Wz*x1e8YzbjM2^`j(0u#K;$7|2PKg<_I^5Sg>H_%Ekac6qWnVMV+j7VIR#EChq9MwM-x+}u1aS4@ zdThP*jcsd$LroN?T44=kGHQ_qkc}eC9@Hy`u0ANVK{Zkv@O-%JX@p@!o{!~`fZaK` z?fOJz;5(8rNKaI*{C>wOVADucK^3(aA*r)wy?RY*njqRi<0bSV<{c1?5mABOvUb1* z{r3;v3J}g;tnl-9Kr<tEq8vlogMipJDytm?pB@02*WO-aI{ zq)#_uT4Dr*hAMa1m;<8P;rIoc^A|%f?gk>G6+M657**x&errs0mwntxl20PFBim4*2Vzr0!d8M8fGe*1 zud_l0h*Vx_@7vpp*PrKvx?5D$+Kov#K4N-#1E;XUAi79C?aA@K?Rw@Nuz(JbcR^t# z?2i*->&Npi2i(CKq8s~wEt7yZ$-tS2+j=a1s5&rQy>jjS^F5A;>sWa|gHwk7&Q3b0 zO(FNM2i(oScFU{WkiC?5`2UXw@KXTpH(B;jxofw?f_8#U!K2fsn@x&c!%lWuIUo&^ zAe`&+2mnmk7B!}ZGOFoD@Sg`3AY2@G^@f1M%7y*PJw_Ltk7+sW-ICSpEWY}n9rWdS zi9wqjD&O$@+B-n#@uSh zko>V7q<2Aoum8Vm_f1?!k@fz%55$_}%BqJXrU^oSFNn*_bT%oM9Ti93zVwn%aPRcX z2D;q{9t9OdOxD^Iy$Kjc3eM(SzI{r!eTt75pcT!du(bMo@XW9auupyX(ajBjd~#mi z4atC(XZNpI44U@$=j9DxuOf&0PkFw1ap#ERDT)0;Xqv#tPaNGhHThe9{8G+6FI`lt z!`N_w^j@XCufr0ORO33|Gf&IFcvocBs&w>bH0rRE{1VR zjlHiFNBu6+DGXW;0H$%InzVK~olxeLZ2uP&3sUcGwcg?~+KgH!Q~fOL87bLSie7mYm-T?Dwv zfp?ev(Z$M)8uDHowic(9Q)Gek`k%u5^{SoBPf~G4hWS zs3es?WQ_Q0htf!&eezGnHK_ZGWcP|_uehqu#m@tm=U?Lzs(CL|1EuUN4)lgX(S;XfpNBN@eH!IS&XOYEPNGa`cf5KAwWRW6!=(B96E_!nBwzCP!I#LPQ22YKUY2gdQ zYo@?6pJ;g0wZre;8m?hKNWPu_c5e7@qW4F5+P(ii{R9Djfs1}b-&}fa3V!R54p&lU z-7;#f3_Nu*{?@H{B*(UE?Wmvydg+Lf(qW}<8TY2uE;n`~0L8s+B!&<|(UR*>4Az}e zBXXnaU~MW(ie}uHKDt7nfkHOtYdxze6s^E&?i$!VP{FG8YuUBTrX0#Cpb0>D1SB;Inhn0~gJ# zt;Co~7L&HC3;p|96?p;L!cQY$D%ZxdcsGM>^XCfo?d-;cPe;Z#yHvIL`_yzup3x-G zxiT$p?iq!l6Qze9KB!?E$x;2#@VKpG=34`l``;yt?58oUB@+q9Te@=u{(-Q2;*DdhxVO+ z@tW${y8tQu4bqLcIdG)4I0$tBU~8ND3kh0R5U$lTLaZoW5j z_|m?flfK+*&&?#8=!+3Y3W6Qvt+_5yU%N=3b}VNq@|{GZi>1Ts+B(Y?sZ48h#KU73 zaS<21;7+^vBHFqxZ-W5v5s)nBbi5pfI9cI79{`5;B`nyaAGl!0fhdoWO ze$+n@_e%4Qf2po?1{sU77M2oE!N~qKZ+aI>_gkODbdniVv8FcG+Oay3qv+y##h_%b zXOYPnDK)6B+rc)jx_47h&mV6*nM-7c+&kX1huP2^{8AeqOsTs06lxPY8KBudz;LXO zgzgE@XcVkB?pUea25Em8r|&ViU6Jp)^Lygu!1c#jJWfdCq`%5n{!EV7(+&LOD>^q% zRayC(Id1NTIzRL5RYcT`)OqOFDo(IR8zf8Hx2W}dIT_DBKbpU$5dO%kGAzKTV@F|j z@6|oiap}zm%)ijL%&j-?m3~0(e{ydh$9ZQ*mPK7Gu3ND31ap!{&L>D`> ze~pmMhMR0B6>8K(Mg|Nqz`=as14N4?6vYo;)zyHMu-KF8pzJx4(}pZb3hAk5Y1%4_ zG*i+8-P;bo^eILr5iM0z)Yw**J`$&T+Eis8T+{w5kj&{JgI$MHPj&jpJYw&I`1E0O z^L@}SiAVHvBb5z!Rz`RA4(%8yLXw3}TkmIFBpcq%xIuw~_0%+87=ItWc@^S^6*BE% zg$;93Ed5lZk5%ItU#{n<_^GLz9;%#;qX^=Uvohr$aazURTJ_U9 z*=*zbcqHdO%U=gUJrgkB&Z}Q)&&FVjDwmWz3Zk}6b0P&^iiKyH+1$pZMW@F8RRtaBImso-33#Rs$ z#=mB-cLpB1wQ@pRF3W3>I|p5&A!ctpP-#=JT8sH9fB0d4;hv-_!*8aJsUw+1C$}p{ z3dA$Td;s#0JO)lNsEhe~#}OT^QY`b>h;zvE8dEcAPHD1yggri5@vtW7#D&zJ>vDwB zTQkcKQU&FQa~p5YkXB&82TsCGn+)q4!IYfGqqkkh?p99)yFT)GStwJVgXbj??+Y9i+&CA1S)%*9MbfFH^H=^go%}ui_NtdURvXj6 z{>LSQF7*`4#Bp8AS8izG`6GlnO1hC74`Si%dB%BILJU4DC&QtcI(;EI3Ro&hIN)d< z>q9HgU!^`s1S%Do&R|!z?Kw1I#MvwZuC<5ANA@KCS(8UyCu;tP1W5EeFg_<0Alpx> z->p=$_dSCsXyjRH(dOSr^O7B^FfY~Quyn7cY;96HTZQ1jcw zG3^UG0`CSUh7mcZb|$pB=ttURBWpJcR9`_d_>2;B|DwN8CvVFc&(x$D;a)X)!ztG(_pr6xU1xnAY#7%y zaT!Z&T-f{)(wI)It!nO|3lqRbfzZ@ttNmrQ8FYtV7vz9sqclDE!(92EM38XD&R%4s z@%{ZhOA&D$mBTa%wu(aig(vYBz6Zuj?zNJOzW03Wc`V}h`;EU{p8@K+>kR(26Ro-t z*2%@54E8&$^iE{H0`G>d-i<2mgb+jQ!F4G63KAb-d^2q0$J1Nz!}$&u`<^nCnaXFr zq-k#oi!XOm8cKOeq2boCdkq~L+@kM=9JlWEp`idvV+EebiS4}g5iJ-jsMzqa z?8l!!u3X+)k^eD&ap?e>*9Qkhp<{+xCC0x25`X#=3h8>&dlycZOVq!{Kf z90o9TO9n)s&=0k|=3`{*>N0jEcnSKH#wLocC+kO)0)UHv3TReW~30=PVSYhHY zgR(+y6#;xU%_c-Z&!eFRw8J-MxYtdkI+~%K8PB&H7~kfSEk&5Y6G@H};9u`ED8NDh z7w98M_CgV?zE}{XC<-ox+EOIC2(50Y<3)zNE{9^~_Y6>91m%J*?lwKvA6f2V9-H!d zhbeP?d-vG3r7h=Ee&y$prT$=EIuoTn(|MG5^3Sgdk3@E877@w$rNE!^Nnt$&uU1IT z5G%MKF9ag!KZ1;2N^7rcs=v2YQw4d_S2%eG(G0#TLYQP1>lrPG1I@qupm57+G zNVV=L!=urxu4tET-M-R;9vv50-ErC7@nuJWHrL_RzM4^+JV;aR_Dp<#c+?gXS||0BQt z$DP)XV)~o1`M~^~0U>3v4hX_nlDa~${g5FSZ&tGg` z%v})_Q-??wfzfdeOcYja$o#oLYH-HWaAaP^-W_(3C|sro`^aUime2#8#j?2cb{r$H zgSHRHunE1r4_9?8%1(HKrq8zPHH5vhg=z6YOmC1L`mr(S#BBEKUuCbw^atnE=t))5 zr-+8yq}pg)iqi14;d?pLfRvl>cXFzUbF3jph} zLGU0N0>G36Fby~~5jMjB1y(?_ac&@G{*W{pwhgE2G}(PD02mX2%%0)BF{;lVULhwP$)k#vk8IbxYRFUR(-C+-#lO#v^W(U61JnPu;jB-7@ z(e*h1k+_`^H!nIgj&A8SdPE(jz+3G7!GhgD>^Qf`$dFgT}M|I_5c(^-Sn)MnWk81R707?K^I{G zLpF{L#ev~4y0d>V_V+N9^NKD2$w)K$JQ+AZCe97$Y;}_1a8j5D!oQ^19|TI~ui ztM4#M=K~270Bp6}JTMbAE3Uu>+1Rz7~d(aKy4htDsdA zlUbZMt_0x~4%k#37TyCrFDYavIAD``ia`Y9d5o%W69_6eXK$)38>B-7%OG~#*wP?j zYmf%OjllMBO`t2NJAE1&hO*sye3*zhAVQa2seAfn(&GUsrmUL_zMgj?9HfIiEnGiD z=L2fSJn#vVohPT_Qzwu1zh;p@D<}zD7&F=$qf1OVI3!Z;4msT>&2W2gRU{+Y0cRKT zj@|>p=&}=9-IM{t>~0gmrGUm=LVX*H*hcP0=VfF8_Mgb#$B8@pFa)fhTubq8P+N0m$; zlNtoI=Fo6FP+O8687 zBX3Mou6pxbh;O#7GIperCsI!}=K!>bOdP4O=_HeW0WkjIBq3s0P2izS^2PsjtM_Nn zVZho2+nkp)^&wk5D&t1dgzrBus}D4(oRQXWUzwLKdj=WsgFr?1c>~UfB+WyE;O@8J zW_ku>rZMZN;ZN0{wI6*TW0s@j3gK`&xqZW?<7lXSN!^Q(n++93@c@qv@ijY~d zUR}IOS&Tfg6yqAGt`%t2ym%pbDK0lKDQL;__hNk4(v_~IOGmOVjxSw>E{82HQNAqE zjF*`ji*zK7ab!6;Hb})aC^>QYT1C*U8_SpLmeaT*p*w4t8dK)w=Ji_n~X`GHVYs)*c$KH5^%MbX|KC zu=Y51EunF>DR<4-X}S6FTFZ%&r(J8Ui=kR_%g>?fe7sDn%zC?VSiA9h=cmw4*Y&Q) zpv00S!2m;Z=K0Q;iCnLyxw55tgAz&FOpCpFk! zgbijXogDXC85BNzhCOm}X(>#hoXQ1O@r^DQnJfQ1i+32N}!|n@Z9_RJ@k}OW2?-}8GbL5@u#sw8qbmW-KZF;5VU^&-vgLECfL+b^A%zpMq z4>Mbb%}LHyWa6fZJImx2&9r_qqHi;4LdX`EoBjxU*Jysv>nLFd@YopELK8NQp{pzl z9m25*oG27w2ReyXQPfnCi-5jf|4T~pKaO2 zNhCSOiI^!QJ6GY|HQ8UDH!_A8uIOY(QvH9fTi1hX)QgfWP1vT(NhLo-r6qTFlMNM7 zJ2W!qA>HlLudZ`))=4E-wI?fpc0=LXK|;Qp9s6f$?%c1Vo_|n()h87NT@3rAe|Qq^ z1M!7@W?Ap90&Lx)bL5Wz(%ES`fcfMG$au)XE`1o0bk2wmqTs(Wa950oe-lo+h{R3c z(7!TYuo1jCe3jo9!@oDeqpdG;i#QhzlyfeYkFtD}&O2>hs1vj>k`sWG4Q2^lw25d2ZW~Dmp zM9O1nF2MfZ$yc}1^BusKTVZ<(X|kLdXwV3PJF$0fjOQBD6#x@K$CgL#P>0A|F9iHk z@P#2B-=b8;jQY6JTRgyEz&4BGd#i+*4?WmOD;_Ik8Wz0DQ?6u@;T~Lfx1i#lMsc*_ zR*VCyE6uSK{(aJ@y`05lIypYei>?HVwJ&Eol!?sNy9OM|ixl|uu`Rkn`t%kv#!JeO zX~CwroV#O8Z|;|sUP-ZZ=@2!Cd3Oe;A-GGyEQsL$wi*+wq|p}Tz{{7F$h5(!LMW12 zsMj=i`a%*Dp{$`Z`CcF-uOQDiEJmyM`u1~;=7`Z88%bfu&M-cIkp+hPdn)`s(n6ig=^5rrF}=>uj9zHr4)qn$42OyN6x=vn!C7CK@?H58G3faSa6SnM}t9D60m?Yz1h92JF$D{)B&mE z`NZib{I2cy32wQ4@RpVVhqK&$a#slLBH9Hi$%q4g37z7{&GlZwKyHu}MTQ#(qBh+^ z=mCgEpS*smJSv?y&vCY^X|;VAQe)xQ=KS!uJ}?;_R>N_5wP)oD=Y9z6P8sAK-fto0 zqKpv;VR6t;iE>fVWsw||FP^D~e}L;INcHx<*|!flHHtx$D18ZBJrR4KMJ{|Zcy~te`q>EzM(4d(ifpF3Bpa`c9o7a z>OJ2>+QFz0%I&53OFd4?M=+)PcTEw(t+5Wv7Ppsb$W2zgEVAqPW3Tm)w8VW+QF^M~ zumFPd`I^b_Q|*R^+oz`EZ&ts}dI7cbwiU<2M~;g~k@xEVoVkAZd7|{~tA~EC+VrqO{Id`?4lC3XByWAZ;H%ODFCDJzufls85e@jb(`#m0nb*E zl0=q;gvGwx2r(v!<55dQB+o*|xE@GGN-$43p`|OqXA~o+rRhYF9h|9?oqxQQAYfQEwhK8# z;t&NX^fNdgsIyxE1W+j>g7)2`K0&#tz=8U*yrCK9)@s3ktc=|4vZ&(zxXcE+2(QcS zUo&|u;9{A6A=odQpe##Q6!1>>Q{YK zBgltL0J;PPQm!If%j(Pz5+af{SOOsjpHNp>eP(p|Jykq`sRufRUO1?R7k0F4*;Hkj zBm;ykg7|f;p|`k#Hz^ahfwfY;oX=k#Hdg3vXgl9~H}=rj0+(-*!jK%YTHb6_ZXjv% zAM9Lr<=7&}U`O|J-1%Q%K>FtpzF)inp5XaS=#IG^W)RC_vHRlWXWRr%u;zZ?yLO^}zJO*h z2?L?GpaTBWnX(a)^r^hf=Yd|85pUx!2EVs5ct@>GFf3Euu#xiCd8~lXD3M1zx4n7u zjgmy#~zocV5q&4_TgvahN+2& zhiwo09qxf1#2`ToFSf3q0%k7mh?fo3x#iuz48z9_wc+gY<%F0`90EFQ8JhK{QSL(9 zqQe3x<|_n}N_wAoS9Lw=P0RH6L#y{ZhgMT+E<<1EwJCnTQ6F7-`RE${XRG9ijc|i! zGsr-PR7E4Ul|#XvgRaCbgELxEq0i5vccb>>B9ojJ+V&b=pB@fP+A2u5~<-T2R(7JNss@Z5!;dZt29UsRR zX5$TY-)f`(HJ;oto7g}4?Lk)Sdcfh!lO1*6A02>gh(-S}>}k8<==p4TkrYF^=g5x# z>W6qofN9wLR8oroe})=RjOx6*tbVki4~m$#WA`wkmnRQL^P&Ga#QYk#6}y#6ze3aD z?IJa3=xKua&saxTOEYK;^z?En$^KlYcA{Pj3G(q|@AnU1pC_C<$`yM!12^DGNxnhm z$^5=mG_M5tZr;|JW)5%4wq{m<@GJC>O{l~=A3Xg6$9 zXBR;E7Js~B|NV_uq%Cy6{tMjs_aCg|+pm@ta%17u`64i}=+}pj?I_;Wn2$e_l+^sW zKer1Zbss(}+wM=Z(gHHJW>R*E#;eK$+ml6C8ySl8XA-e(rhbmXsYP=Kl|Z1LU*R9) zq<|)y5+eE3tD{Bh8{G&wIPnT~we}3)x6+j1_ha!Pt!loE`S}D6w zjLO2n2&Rgf&~mM} zeBUIQf=@n zQ{R*XgZk}heJwlZNF4KGOP9!VC6A?Vwsm0QKG40f7HfD zWXQtQQY}?^*6d*knXQb0W(dJMOfAdeYJ3jte4pKKMkDsL=|^-Z)U*+TI&f81=7V!V zCz&Q`?F14}n+npPF)b@BL~7rXNoAIzD#{XSr7^RbT_tWRuQhVZ$&dvHnFU7;bw?Mb z`EL=5Ss6G&J#}G5(IQ>PLq+4A3f`58|8Him#fVxOgUByARbMQhE@R+UdTkfp`t+>5 zi?YAQ2kD9)xq^;aQ@(;HSi+hn!(m=qwy5m^nppFt*kBi(4h1*95eEX}&*CE}N>Xhn zY#DGZwpjx;L5GF-d&IZ8X z9n;@Hs%{fT)+DWEhLAOXAInml!^GRR!QB9+qy4)9VB%KgRb!G82OOnBH{qe@n>E5z z0$f}=E+$t(mdQq3>r1KBfAPNM+vK;_l|tF1(=}v-oF%NH9UrrV_3WVMQ?y1|I3h#^ zk}8DVlm4F<5E=}IujFwmms{mwjTVu)eTm)KP?zH9-g z=14#*J_VdFxe?chdTT3 zCXH=r{wAO4m$T%b+bGZXJ?hfgh+p3gj3`6ZsNurU zO76gKThP3O0CKE4QGeog^~xdL^y#2yxilQB!;P_O>Zj=8B5sN+%d|M7z2idJ`UEl< z0AkgU_F-!lqh~)KlGy}NwH~u~k}B+N*U8HvUu|gnjpwC~(Tp8LO|xlZTIaVi>m;9d zm{@$|uE7$pXdfj1EiKx@@%Xp8DOM5J!_KifA zusFqrSad^0Sk;qa#4Y{lbl+mS>W>*oSXipZqH`zzGnq$S{1@Reb&s3-`B%k#@hAJ^ z+qI(->%lC-zmkt+zOKXXPk$|VUvfW?|0XpU-{=1yI;$ud_mu?-!k5_;QCpi`<1@s{SP}=?vn-QS3aG8 z=@A+~0)Q5MhRTw`uT@1=BKB{FZcO9%oj?7lu!n%^fQ?!1F1Dg0%g%JDBYdKSi=sgs~HId@fF{J!Vg`*L-QrFg5-r!h+F*+Z%E z{Te!7pD*rDaD9lEKU*#Zx=sM;>R3g1>e{26W#|B1>reQ!28*{KWuSWWJ4vE z(OIEEB$#mE^Xus#q`ji0Db2Wstn!&qdjTl3v}w_>X?PoWS);@Ze8yZ`_c|*W)o*VV zs63H4?O<-OZoFYA8GYFIsPW-Oa8RVp>4(TYlskqr4YmasU}(R?wh%G;EcfRlLcUYq zr5tl7X74Gz-fhUS7GJ0RjkeCm>^{bj*6J-pr6uze}-epe+T)7Wvmy20AiyMw3B`!u9^gBKLG=4&`8$z ze2j)3d4cgpPXcAJCj)L)|0l=t(LVB3g7VjmkH=Ypv-y44o46*>(;=EgLp13cdzWBr zy&UVZZJd0Gd95s<^-9%Q`(&9ba46dt%K7feJR3S!qp(9{`eXy5WXPX?@536>q`6=M zIYw&;6enY0yl&}uAV?(>{2zfd^G7tR3P}*B5C^O)$fbhKd)61;}6i{HLb1&#)+_np;+Uv z{#Y9x5Az{b>iPZ!ciLH{pxBhk6oSdL#E(+kHm=g>cEh-b7+WleVVuphg4!z)!NhGf z9p49IbwDe@Et5Ekw%{>dbJmasR-JG$vIRqSiZKyv3(H*4({=S3 z3&UkQI)S!pqx4hx#4sT;&75M4BlgLBj4w=?v01}ZW-Y1x*eVvr*)qT3(?A6dENvpi z*|yz?#Uz9+fqZE=TZ$3K$ilXx?#CsiO;@X^DPo}oZ_jVa#Ax+RmE_rY`&pepvkq@i zdypy91Sfv}I#_oXQjXhq_zc*Ddcaq;li)&mC{&yI{mET>Ve1g4^`RRLUoW*`FITKt zzu0Nvt_D=y{Cxs-#VF`^N<_!q<9d#92Wl>xvR`xWt;H8>|FVc+^m+U0I2wZ zOHVOewA%5s4#E|9#M!CmuUp!$n^o_e8fnk^UAgouq2>Cut53lni*SS>s z`nSdC)6%(1r?ivBnm{J7-*6gD19za|G_79pj|~3E?W?UJt<7!QFF6DGSGldPa}FY( zzPrjxcz-|P?zMl{st#TqI;gd;T`aZr{Y~MC9|_vM2L-~<1)+PPam?~PhiE@rXYcQs zHF-XF_|Salhgtjoepx>GUwEtSwi2%6Blp@Cy#6q)M>`L_ib;D~ig)@3~*xGw00t56 zSKSTozDaA{&2yO>*L1h8_igz*Zr=Jgl&QO2)wlgXcd)SULx$*w$9*54>Fzx0+d0Rz zv&pS<#*hnR&NV1OMIA$J=}Zhxy*<}6KW;gF z33`+etIMx`hW+r&;Xo3(=ZA^L82Lxlqu=*V{(Sg|=JQVpDTSS&5RmT5$HWa~%KaYS zKW7fsOR5pH9L#iCE*uY`QgYRU%N5kN-0RPs3{02Ma43ID0}HiwSlph=SvLt;Kzn{1 zQot%Jik`YsB4y&)7SLc8u9h~--V(M_I|B#_933rHo)Nxr;NmMPKX zwa``If8l}aK#G9&&47z7-ZPc<-8U~^dKk1iTJYqgo^yBP-o`@rtsvJ&*MOXYrwfBA zL)Uq}-svt3ac|7C%y~J|aE=FM1T6q4*IOmJWMVY9!YqhJLcG^c$`CCV^UHcUG&?>5 zTD+!s$7c-J4v*?mutm4T!XM4$$$l9G2ZFf%xi&FmD?R4e+`#1Qg5^)s%h=9Ph(SR@ zB;8Ml3zpb;kxo{!H?(fR;#MRF2KgWV+}m7ybnn`=!$Y8xLK6_8Fx?O4F}E7%0R^D+ z#w3O$TIm!saIzRD#s|Q+@1`eai%*iBMxJ9=TWc-w;9NuPWULmYx>mx6E3}{*2%%Kou(k*jSg~t<|6)rQ_ zLTj6z0X0ixYuSotC4CX_K$l9|P0_2GE8JB(NRCZo%b)z_} zChRCe+T&|fbHi(CM8w-BcT70gDdD|;vBpnq_{)e*9dV;!%4jmLlGhd{FyM3Qr;}1h z_d>ry(}?VE{M@d8_Qrpr_rA`Yd({7BJfP{!&o?V2e}BDy@aA9c!ZX*yzXx4!j&>kg z4~S&C|50TDznbW=E756)a2EJQf*!;&*aOwdVplHIM@(fWh<+otsH2HIhd1a+lJGfB z>p~)X5j|Nkd=*A<5EPiAr=+H>B0>rcM7@|PI^R}Zub>U_$eh&mgH@g!pIc%|IcXN* zWlgzgqvN_c>GrK_0-wc=6sJ%b&fnIA2KEaSZ{%cps=XDSDKtLWn3Hum{H@3;+C+0I z=SD>9ThYBj6P-^v*>T_A9tR4O^pUyrWVLlXPZ7yTDK{r8d|ezbY-(zmn_JMjE-5Q) zY!R57cW$@>t1WD1eSr;J@Y#d5FImm4?-WDcpK|O{zSaBf z-HD90C+eWQ!V$HNYf0my?n-$@Pm|87EN+?mTILm#X_c5~%@5Ul@Q2byYGBn&;JwC< ze)PMKm3R0yQZg?ZYJM0NP|a@<*sk5sNsO{kD^BJ}cNoU~8<+edu;%2{q$f9= zlVvwB0)L62U65cU$fDntAgv7L=M8dsOWe>JG`=JMvZ+(SjYkP*ec`B#s`(LePw{D$ z?o$Ur6g=UmvjZq9h_~9CakF!_W-F_-nrSc8FAl{ zi#&lX(UUrlevmBeNS>nvCk2qDz)K3Dy1HH9OmsuZjNiD(Zq zg;Yy%gc5p~U^!9doT{#XV1R@yk1DbC0-W9s102D@pw3ZSqi(c5PxJt1eG=tC+{wUO z|1h@Ag%lKQYmAE_#Tmh22`c2ePRN|G)r1@JnTG0}kiws-XW^huj0Ds~Z~{jO73K#R zf@*yMDR8Ye_(xFPO;y;dUI*9~?2sUZrM8Ws?cyiWNf#s-DFRFi*rRkn$x``Meeg+p zRjR`IA69me6uTY?2rzL~8mQjWe>cq2F2x`bVi9noLsa)u#zEdo6^<)BlJsTVEZz0a zZwurGSE4|Na;;dQ!R5)+r-76D$lz~^@){_EL#}yhqJ&y0P=srM?Iwc*a&%*j#u5Ns zOqM*KvtEs(_lp(2l<^|iKT2wwCG=~;70rEwMoBy8845rGiy{BUgTp4dn?5%+a95&q z_vsb=^YRokl`EgpQF<8#+%JUW4~NZ;Z>Q0m*Y}M_lJ}~9io2^!Kx*@ zA^67Z<5A8OqsOIKHatDd^~s#~ixvycxAZ+py+5U`4>wB$Bo?SSu?1t?g;bZY)S_B; zFKmZ~WMPW1S${PzNkjfDg9y&0vgc1xU#fP5@mx6)m`Q+|cl^F46&5>}V4jxP|7Ri$4N7D!y1!;lYl|;={>rUbPBI5ayPLf^St6TGGsNJ=X zx38YZuW(mgKm%JwA#veW8|PtAfc97!co@Fkf8WI+Szh#3OoF#On|c!UNzNPUk)wP1o99B9%O8H)Rutg66*{hpGHV82t2h7FT=gTFdAO_ zfmPhzod5hRSf6hma`;0%7`a#m)*&dOl-NuYI6|TO9FMsN5|)Oa!0Bc~tqCQWlt-i^ zt(3OWT4n^uQFf~567vkh?a3?fYzhKP)@p_}(w4vC%eeSyNGAZ;hm6{% zLQjsZH;dhO>ThlrE89Njd<2VD_+6YNmkJu}najbQ8G?}Ie%!Y@Eol`yHGpN(czVvt)2Sl0Nm|UoOLTU=01wkiHzbqxaggZp zDG}f1cF6AlRpO_Kj7}@F zA;P9Cjaow$7%GY-G%2Qvd_c1@n$|X!i#Pty6p%$^gvfK4!;bIdc+Zwjx zx~*0Mo=%i49F%3O&B_dl5yS+(*dWc5C0g~+y4N*^^#sIR(RsxuQB}uXsgKsxeCO&LWdK_i23bF`5NJRO4>25;`EfbPUG4auYQn{ zmDIEiSqlUiTb0D*8QRQxQf`WnhOtumN7KXl&;ksJMojmMRTVlImX20}@b8hpfaihL zJ8p|O_ftQx*cr#kBbyVz?u=KPvH_6|)Y;_DH7mmP`h82=?b*D%TyLres5|tEQ_|g# zjX+45u@+WOsASWt11OkCvOU9vD=^1S;RQ%ZhLE#%Il1DK0ByeKHm&QcBrzkE`$AId z3U?|z>jsPhJh=HwP3wT@kab*Cl0-aPSW$&cYLbzj2QQq*W4R@?)X;2e!)zx5%raRN++5lanmmt4Pqm1;ff8Und8=CUJ5(;X>q6A;s*-CbxKdw%AL2iK{=u zc)XNH-iALmAmXa5r|^)LoFMH~TV<-V%{G=8aqdc<_(wTg1$Kv|~?M+ z78ZX0NH2$ad7ugIJU%!RlIIyykiA{9J$(U49@(T1L6R4ymjcyFg$f6-&o78yDz$+dQ6GJ6){7D{EDF4d z_thRSuHCmnZ$xABT%|nBhVb5|34&PR*SL$cx@4L-heyMZHEyKV{OeTkubi|~l4peN z*sh+})i|xhk*@7#k70Z*QAxJHnxL_elmUo#>j+=AMdFqWWk=ltH=Ub39zX}KgFCnh zfE4LWk#<;6Z7GWQm3(A!#d#PHw8%icVlLcLb$63NSBi%V-1LrgnF;6ryA(P(#@CqzzB>cEaW1sCh>1RmaePRi5xms>Xj zS6OPnye&bBd2My6&Hmj-4oa0yOWYA~=>h_;u}W=J`Zl}!1`5T927Cd-Es;{<#VgYK z3^p@{**5|7z@;ATVKvdF?u@b;9X_8*etDCuanOm=^|^q5ppJX zmM`8^B=a_|cBLk^-t*udrpbkQM@Cn1$3NDt>bR;a9d0-z+=Ks`?jNoF9Y0kji^n|{?yt&}8e7tRk9>7k&I1)lGFI&6<34jvrC6gO?q zxV<<1m+j-IKZe|zDp#5?tpi4Tl_7eG#+Ug`49a^lh9+m6qF1o;PJjoi7viG2;&zPx zQ!nE~^WEc~``-!Ne*x5>Y-?>kF(|KjN)_Rki>#$!uF6{*==eqn%cCEMVDtuk%TQ+C zLeMT9BbxbH;05SOU!Dl4$DQZ2jfsNCWyPCOgJDmkPhK*Mgu2{L^N1aFg~u-uRYenD zw-9-VbMjlW9i7BCBOvgWy7jx1jeq5Ti`*Ea?4u4?P98|mulzNQ-gTesFdV|MqNP2W3bU8VE!*IeQ^e2*!*xm@$p-HdR_ z40MUR@^6#YCm#KJGx4ZQ8NW66c&p&wyPRWjH~+o2?t6bfe!He`yW!tdA7^xT7UFl7`*vR4&1UF+GWfT{Y4~a9?(z4!%Aevte^CB> zIrTHpRrK#a0_f51c*rhdXjkA6!}EwBc(`ZOvpnjMrKk6hC%cW95f=m_)i`Z9?6FEYYC=L#84(J>;|L2*SEv&n_ zy&R@Y*-(%O0q09N3sI{XyE7U6Pr--3W;R*6xf=MjjFlwgH^F79ktm#+%_Dujr!b^; zr7hq^R~+nAu*uv`s>^WA2HSyLdV-r^fQY9HZwBqUS1LrNax=MI{_B3WhUtQfQq$x38{HD*`b-~ zIhQg%+5YA4pM!%#ZZfs-q%oPsaV(Xb099HNicD0nn&#pq;jTx5T(+oeg-PO>$|agO zlas4HZUe+#^D+^Vh*by&S|hd^x21}MK0^9j{NZv#@PWaU|_WhPiY@RanZ)ksAyy%{hKdlEztWbXE$#j#tu1Rqi zKzJJ!wir7kYEY9-ZP39;sU$a^5xt9=OrVHH0FDk8tS1aW15n>UBGM#4$_?U;A6EQ! z=DP_Ph;j&rh<8a2ovrdR$}hi_F37{htKg;>-)?=;FGaP3K57lyamx%=D}t;kWvO_W z>kFEfj~HNm^$kwArnIHPGQNGWMo*ewn0tJPKQV72&r4>)n0}_gfxLE930Iz^P+99x zgn82w+2RztuTM44@P9K&B)A({oDS+n37RLZ52|Ge#s&{w+&C4m>~$~e$_jpU;>wG_ zN3YZ`;owA*G%p3W(Q^fmx*wNXKbB2w4onu}R{uzvpS?bOTY2!p zU(_e}grmIe+qe#?JCj%WbK;Hi9r(UX9BR&(cAbkz!0^_ybbOz?o;LW!eQln~9((%S z+_B~C=3ekyp(NlN?zF(8ty!sIFmm_}a;AGFry+<}X=cv<6$MR}(Ge+7=x<8-Qb*5%1rY~(0My?~*=)7O>! z%v3{3t^OLgO$mq(q`ZKSpEOO+=#0oc2%17~$bOmCW&zkfdiK_J6B9IhDFjq)d7Q$URJ32ip z>CQBTVS1{HpKIPrSPH`nGT#_zypy$}Rb0Cton@TcIVqVETE^e7l`NMwlj-+OFVI&n zKxG)E+f%`oF_vd!(99W>Pv#g;7}EqOgEdL_g)%fY4J4RJD04D|sfIujQA%=?u-FsD zrC>jq3YjEwO=;Ot_!ZDNUm_L$I-!vxMUE@>s{~u-h!nyTxs`(T%Vjv8-L^D9 z{udzKS1URUR}T^&WfI3T`2=+*_4pcmmY+~n789tPkm98gTR~++M|#Dj^_8QmtU6If zu|5*qF@?t1;Kzh~E9NtNJw;smBBxAQqq-(gBng!uWVjmcZM6+;eh2uKUz=*QB&XV? z)t|S0Jmn;q`CEM!T`ls7dQ-3@MH2@wfIqsFBlFNluoh3;URIqY29%j0d zlj$?8NXW-SPHg2{=M*PPHo(F_Nk;{bQSKdp@8I5nSzS5 zui$wWL749FgleHI&;Wt|16A`I(NYqcA(k=&wGdbx&2#2d@m8>ngqz z58oB}H4S=7E=cnD%gJ$%^IO%17NFJ1V5hx_b6r2${{FaN->cZ1lih<_m5UmGly#OZ z3nuU+KyaM9=*zYG06tazr&3BN7e_&r)bjxfb`=-X3LtHiJS9We5W}4`4B=G}N_rYD zF@Nm0!(-=fNHq@-?e5RHGpjUSAD4LL0`4pyl1kJ}<`sq$!IZOQmW+zk2ri4vpfzvs zTvfWdq$z2|l}#OmYXZ}Ry`*?G9=)5_6E><@R7uovz)Uy4&SpEdk#Nzwdakpt^}#iZ zeq&h7Qb1mY31?HP$Jc@B{y=q$bp;&i%hMFYbHBygXc2 zdf53a>r+>F%&U)H=3Q?PpRYcNdHs#Utow7;=Yjc{H-A1oe01o%9t(?QMFTqqxNqzx z$^R*13)=4$LhhxWja}pCOdC4U_bL71Z|t$~QC#)oo5YW0L4`g?>9%n}iQu6}o-KMO z2jz0DGyeogUr2vKxlwx3$6ZMcmvYJhDTFE+8fGs7t8?rKh5`Og8=FMiBw2owv44x1 zzj1bMCXLJIfb*@Bbo=OK6{sT_0Cw&$_E``M&Ash}>_Vmydgkiv4DXx?dI*tnX)r0_ zej*%D1rdj4Mgrf*PE~|w5PBShs^>hQWvGYcT{Yn?6oAMdO3&MSy5YrSDps@TFqU-s zjo=eLKcQs>msR1{-{)0-eK;x1t{^DJ8PXxS<0l`b|9s^NJ<0tOU`5BN^%(BuT!lb1 z;9oq)XMkSGT}75d^t5WW@Y*$rFP`$CQ}dNqb8xHJb4~H2p6nuL4^fE;*MjY54?LdF z4SzqLW1xYx;XV8n(MVv>yddFz_sQUAw(z$4T9NM)Qm;s!6!&i7}%-sc;8oTz&> z*~2Hrrvr70l*aAAwh)Xw;tahA+21=*Ur5o; z;BEq>eD?+(oL-h1y;YSbd_P{969%QRE%XZ~vk=8rY?!@kI5IFX7$HcAN+$y)nJ_?g z+7dry>FA0!DjR|h?IHttgQ4jxfDZo5Ej(u^8K{OsURV#!V5CQtbB1pL9O=3Fv&J2_ z5{}Jq4zaA)nH<)_D$7+@O*``~WPuxWsJj^Sf$EXNT0mljT0uY!Ea>}vo2s{P>NFss zlS`EhOioS?Fv+(+OiY#COTLu`ELsMH>A~H_Lepjov&U0zeNWkBav+!-uW>h3$;j6^ z*V&t{$H@S%tQRHUM@>$19v_J0orYyHP+w$#QOkfBQ;eZ+KIwe{S@xy}1SHEt<@>5I zb_(*70$gXDR^4^W@df5xEJC7?S0iuwcHX?a20zBbvCiO0{Z)`b&bIOfzOncMUk3XR_{gzPXT~(+x~)Ky_C+K;B;GwP+W;IN<-b5L`Fi1`5)0wa0yzIFpg?%m z88BOxXgYzNAA~&7#Ibk*l{B93+6h|$a2ZX@)Ub?r`_tk&IYf#}#;Wcin1wvgixIoU zJVj9whqZT+;-qX_QPYO&TQh;rfm?zGthJrpVVB= zDj+ne%e#iGDAjQuiMlSgiclgz9)wj3f+C{2P%+zp`Klc50eEo@uNMn(P9MB!1&Z0{ zZ@(2M_BCEwrdWZm_{w{mwl2~0UwAXA-gW7^s?#a#*0;~-*COdTyt}uRBuhFRkG_gU z$3u?gUA|Vj$ZajxJ6)*AiHbB#e&%*HZAI!%M_8i4-PL}spX;?uxw=onSEas4t{wj5 zNxoV;Yzx|Cf&OlbCQmD)amd%onQs>#+z~_`D`kJl5P4pEf6<*IUq}kJ3I&?U1`w0Y zChCw3NIAVqud_NPHJq1PjnupUbQ@5)Ei5YrEujDdZJH8JB04%7tD_M(75GrPcX@iX z80r_%KO;S@Lv~!~xGR zlamU_-8Cs-y$7&xWw55WUP3{yRf{C<2q?|^3Fd0;&mx$#B1KpaJIAK+YjVgRUA=%2dJ12%Bf~`?4^|twb+ZNVUuL!;NknWQKdnlN8G4Pqik=jlgLPc3OSQL|pM% zk>!URp_=S{88OE2rpmgT$TrgV%Mnj^^08oFU$RM94H?UZ_qI z!1RqpEQT?mzzAL(GO)6ierj-0`l1>QvLl>((tp@pVFEYMFOEWbS&8u~lwa;ak8Zb7`5wZ9Yvx&N&Ti2R_PtSZh zM0}WCf0&yxEG~CN(28rB3Y64C#)=)M8i0F!gFhAZ>m$3Y6Uvb;KbnqizKVQD0kw0xqz{$pa-BMH?>^hL$T3f2U6X zAAftvxy+imb`f#>I*`di!RsrHb-=s~uH;i()SkMDqLQS^#xFw%76AEr8k+re-n!w5 z0Gh9Nw=OH7TVM%GB-+ zDs^>=g}_QV680Yy9h$5P2I4JrunglhsZXHB;3QLxMbEhPXKz76(=egib+ngFi9MnY z79us%+DML`G}Sf9yS$Es>kTYym_>JXNsSVY#?3L<)&0)-Q@r&cVwu2~v;$~l!7FH) z`Yv}eF9T&7*LH7Zc3T-IvsN?uA=`eBLBAS{3D?V+%C;`=s;yThpl?;~iae8qYr7b4 zFy61xp(jG>((bo@(vI)F3Oz#ss(#p{-gsm;k;|eZ&iC;WaG80<%5i?%E)^ zG^zyONQO5uIfv-H%JRt8U{#r^_1mN=Mizg6M*+ujR)5`Vg@6rq+Q#wHs}rxcVp1{B zZ|tx|^e!FVeXD)LkA3xxHs|$0ef;a)SLvs~g-XC>s@UNSi}Q>;_tbG)DLMa{U3L64 z7yq96UPqJUtw*Q!VE6V8W_E=XhSW>h7s$TcuBdbtR1)+erC1o&z$8qOhZO z1O+~WgpPYF1;sjBAuvEch9h6-G&>++*XZ+QX!f@u6>uvxXY%g1%dIH2pNGV*FAxy@clqU>9XI~`gX7D$kP|<{&i!QU{fPV= z81dj|%(I_yK_OSU_h~2g6VL4@2kl?a-cNh5pYd!z>+^m#_ph82zw*xgDhT>@EBjZ* zwJ-!3Eq!Q$jzI%%pTm{=qg6Q3a^CE5GvU{)L(_l}McfBXCk|T99VCZDUT-Q%1pWpF zAEYTqMeF}gp5g3V6$&{82JRk2;iKbcey8sJZsYztbK>uu>p@4=!KNPWIp-e*cXY|& zub1S5a@KDHlfUnR{%vOeW8eAZIF>w|4J>3KEF3^UYD_sX-8Tj2MCLk_U?iVI#d5;tAHO0U?6#ULF%H6DQZq8VQunT z?Q?%)0BY0AaBd63Wt zGte#awmArPMU&L^l1qgtnanT2mFDND1+82^2J6rCpU(KC&KTSF%ocd8A}#{=J#5Ot z$q(wElW*j(VM_4ZV}nhlZijy{l_}2;HIv&6WlhM}Rmh)h>rklc2ZMvDMY=v3(y9rK z0n@4pdLQIeIc4T22g3+(a;|M~?Pwtd-So8`r2|z3s674XdCNJv$k=FoGDNwngaHfJ z$^(=dp@T>(N&rYJWQaY~4Ce#2h^CB|;1|kKX<_sxqkJI4Za$ z1=J4$TIbHkTvklHe3j)aO8R<1`EAP8CHXse5wLYfO(j1{tFPKWpkyGiXxayra@)BT zS4CXd9{#}(`-U*XN;qy?VI9#TcAq&E3fGH+lV;X7)t?y!eVuw*-Sj^^Y2}m9k)oSU z=t`jr>nIgxq3CfhwCXW#z3^EJZtBg`%UAwIZI$1OkM7wzY`@LwXnCd*liIo27ucEC ztGo6PGKf>bwE#QoIVPm4;|5rq=JDGf9v;U3`FiG3%-$;U+QDJ+gTQ`}E8yLzWY^Oj z3J>_+QBQfM|L`ZN-{oX>#jE;oFBAcOU=IpP*4u&5X&$CHt^;Y^hmhSQj0XkgyiY{; z(GxkpksI_JhB$stoRumOf!I0-Vn?k~4J6!nvI^xt?0rte|9Jy_W-|!TQcj0{TjgoE zYNX(0opJD<41OXl|1T;i$-U_|zx)HPP ze*CY@a7vtVhW7m1G;8mI_bB%TZ^YHf(NnuX~<|`*oJgVSChK=cSw# zWp102dw$HrOZCn#b01^d;<*a1lMPW80baJZ%k4Jm+kaUEr`VRfmGIVl8f6(?*>dw$ zeu37jUzS%#ZSQ`q@YdOZOi}>={4X|kC;$jhAOZjYGXNR@;Cc=KpC$>NxT6?%?-<;n zgFqd+juJO3AvKkaq=GqIx_5DR`#7N|(y>uF)bTuNX|IaWJ$;F|oMZG7Q&qskZ5d@< zRtHnOkA5=IX4rIIVmMRJ`O{atZS~xBqjKFz4e~a)(&8R8YobkTq1G`mRMej*V5!)> z`>yi`f~R9yz+#`h$b}D1H4!_nlW+fg@6s3d@L#X+(tGk?^2jmEBJ_@1d6ww$8}(OJ zJjY{Bz!sFpi!?%}j+OS;X>N7SRgZT9og8KS=Fg!X3jR)_aq4VXes;quxYz(-Hn#sA_-_r60Is6}X#g07CNUWUiELn*|A=e76tJkElSYmhFik+zFBTnA b{x|~(2L11||DP}Y{|EkG>-_&*67By3sh%F; literal 0 HcmV?d00001 diff --git a/docs/sidebar.yml b/docs/sidebar.yml index 4b47033e64cb..7a534eb42ae8 100644 --- a/docs/sidebar.yml +++ b/docs/sidebar.yml @@ -2,10 +2,8 @@ sidebar: - title: Blog - title: Usage subsection: - - page: docs/usage/getting-started.md - page: docs/usage/sbt-projects.md - page: docs/usage/ide-support.md - - page: docs/usage/tools-worksheets.md - page: docs/usage/cbt-projects.md - page: docs/usage/scaladoc - title: Reference @@ -147,6 +145,3 @@ sidebar: - page: docs/internals/type-system.md - page: docs/internals/dotty-internals-1-notes.md - page: docs/internals/debug-macros.md - - title: Resources - subsection: - - page: docs/resources/talks.md diff --git a/project/CopyDocs.scala b/project/CopyDocs.scala index 29760ce85e42..d8bcd4474824 100644 --- a/project/CopyDocs.scala +++ b/project/CopyDocs.scala @@ -45,7 +45,7 @@ object CopyDocs { */ val transformationMap: Map[String, Set[(String, MyParams => String)]] = Map( "docs/docs/usage/scaladoc/index.md" -> Set( - ("""\{\{ site\.baseurl \}\}/resources/images/scala3/scaladoc/logo\.svg""" -> "images/scaladoc-logo.png"), + ("""\{\{ site\.baseurl \}\}/resources/images/scala3/scaladoc/logo\.svg""" -> "images/scaladoc_logo.svg"), ), "docs/docs/usage/scaladoc/site-versioning.md" -> Set( @@ -67,20 +67,6 @@ object CopyDocs { "docs/docs/usage/scaladoc/" -> (commonTransformations + (titlePattern -> s"---\ntitle: $$1\n---"), ), - - "docs/docs/usage/getting-started" -> (commonTransformations + - (titlePattern -> "---\nlayout: doc-page\ntitle: Getting Started: Users\nmovedTo: https://docs.scala-lang.org/scala3/getting-started.html\n---"), - ), - - "docs/docs/usage/tools-worksheets" -> (commonTransformations + - (titlePattern -> "---\nlayout: doc-page\ntitle: \"Worksheet mode with Dotty IDE\"\nmovedTo: https://docs.scala-lang.org/scala3/book/tools-worksheets.html\n---") + - ("""/resources/images/scala3-book/intellij-worksheet\.png""" -> "images/worksheets/intellij-worksheet.png") + - ("""/resources/images/scala3-book/metals-worksheet\.png""" -> "images/worksheets/metals-worksheet.png") - ), - - "docs/docs/resources/talks" -> (commonTransformations + - (titlePattern -> "---\nlayout: doc-page\ntitle: Talks\nmovedTo: https://docs.scala-lang.org/scala3/talks.html\n---") - ) ) def copyDocs() = { diff --git a/project/scripts/genDocsScalaLang b/project/scripts/genDocsScalaLang index 1404cd5ef0f7..1ce53899fd33 100755 --- a/project/scripts/genDocsScalaLang +++ b/project/scripts/genDocsScalaLang @@ -44,14 +44,15 @@ fi cp -rf "$SITE_OUT_DIR/docs/reference"/* "$DOCS_SCALA_LANG_DIR/_scala3-reference" cp -rf "$SITE_OUT_DIR/docs/usage/scaladoc"/* "$DOCS_SCALA_LANG_DIR/_overviews/scala3-scaladoc" -cp -rf "$SITE_OUT_DIR/docs/resources/talks.md" "$DOCS_SCALA_LANG_DIR/scala3/talks.md" -cp -rf "$SITE_OUT_DIR/docs/usage/getting-started.md" "$DOCS_SCALA_LANG_DIR/scala3/getting-started.md" -cp -rf "$SITE_OUT_DIR/docs/usage/tools-worksheets.md" "$DOCS_SCALA_LANG_DIR/_overviews/scala3-book/tools-worksheets.md" - - # Copy csses and html importing these assets cp -f "$SITE_OUT_DIR/styles/colors.css" "$DOCS_SCALA_LANG_DIR/resources/css/colors.css" cp -f "$PWD/docs/docsScalaLangResources/scaladoc-assets.html" "$DOCS_SCALA_LANG_DIR/_includes/scaladoc-assets.html" +# Copy images and resources +cp -f "$PWD/scaladoc/resources/dotty_res/images/scaladoc_logo.svg" "$DOCS_SCALA_LANG_DIR/resources/images/scala3/scaladoc/logo.svg" +cp -f "$PWD/docs/images/scaladoc/nightly.gif" "$DOCS_SCALA_LANG_DIR/resources/images/scala3/scaladoc/nightly.gif" +cp -f "$PWD/docs/images/scaladoc/inkuire-1.0.0-M2_js_flatMap.gif" "$DOCS_SCALA_LANG_DIR/resources/images/scala3/scaladoc/inkuire-1\.0\.0-M2_js_flatMap.gif" +cp -f "$PWD/docs/images/explicit-nulls/explicit-nulls-type-hierarchy.png" "$DOCS_SCALA_LANG_DIR/resources/images/scala3/explicit-nulls/explicit-nulls-type-hierarchy.png" + # Hack inclusion of these assests by the docs.scala-lang jekyll builder echo "{% include scaladoc-assets.html %}" >> "$DOCS_SCALA_LANG_DIR/_layouts/inner-page-parent-dropdown.html" diff --git a/scaladoc/src/dotty/tools/scaladoc/site/templates.scala b/scaladoc/src/dotty/tools/scaladoc/site/templates.scala index 3149023d3613..8ca2601f9b63 100644 --- a/scaladoc/src/dotty/tools/scaladoc/site/templates.scala +++ b/scaladoc/src/dotty/tools/scaladoc/site/templates.scala @@ -132,10 +132,8 @@ case class TemplateFile( ssctx.args.projectFormat match case "html" => HtmlRenderer.builder(defaultMarkdownOptions).build().render(processed) - case "md" => - - FrontMatterRenderer.render(settings + ("urls" -> sourceLinks.toMap)) + - Formatter.builder(defaultMarkdownOptions).build().render(processed) + case "md" => FrontMatterRenderer.render(settings + ("urls" -> sourceLinks.toMap)) + + Formatter.builder(defaultMarkdownOptions).build().render(processed) if layoutTemplate.isEmpty || ssctx.args.projectFormat == "md" then From 3b2bcb23070675803b7f28deb8b1affbfb69bd99 Mon Sep 17 00:00:00 2001 From: Andrzej Ratajczak Date: Thu, 14 Oct 2021 15:56:44 +0200 Subject: [PATCH 0732/1244] Rename secrets in github workflows --- .github/workflows/ci.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 037229da32fc..70f69d1fd568 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -500,7 +500,7 @@ jobs: - name: Deploy Website to dotty-website uses: peaceiris/actions-gh-pages@v3 with: - personal_token: ${{ DOTTY_WEBSITE_BOT_TOKEN }} + personal_token: ${{ env.DOTTY_WEBSITE_BOT_TOKEN }} publish_dir: docs/_site external_repository: lampepfl/dotty-website publish_branch: gh-pages @@ -512,7 +512,7 @@ jobs: - name: Deploy Website to docs.scala-lang uses: peaceiris/actions-gh-pages@v3 with: - personal_token: ${{ DOCS_SCALALANG_BOT_TOKEN }} + personal_token: ${{ env.DOCS_SCALALANG_BOT_TOKEN }} publish_dir: docsScalaLang external_repository: BarkingBad/docs.scala-lang publish_branch: dev From 3538652e0075d51ddec9abd40e4c5e83d7aa36c0 Mon Sep 17 00:00:00 2001 From: danicheg Date: Mon, 18 Oct 2021 14:39:16 +0300 Subject: [PATCH 0733/1244] Use IArray.map in Tuple.fromIArray --- library/src/scala/Tuple.scala | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/library/src/scala/Tuple.scala b/library/src/scala/Tuple.scala index fb08a0afe2b5..784170c524ae 100644 --- a/library/src/scala/Tuple.scala +++ b/library/src/scala/Tuple.scala @@ -228,18 +228,17 @@ object Tuple { case xs: Array[Object] => xs case xs => xs.map(_.asInstanceOf[Object]) } - runtime.Tuples.fromArray(xs2).asInstanceOf[Tuple] + runtime.Tuples.fromArray(xs2) } /** Convert an immutable array into a tuple of unknown arity and types */ def fromIArray[T](xs: IArray[T]): Tuple = { val xs2: IArray[Object] = xs match { case xs: IArray[Object] @unchecked => xs - case xs => - // TODO support IArray.map - xs.asInstanceOf[Array[T]].map(_.asInstanceOf[Object]).asInstanceOf[IArray[Object]] + case _ => + xs.map(_.asInstanceOf[Object]) } - runtime.Tuples.fromIArray(xs2).asInstanceOf[Tuple] + runtime.Tuples.fromIArray(xs2) } /** Convert a Product into a tuple of unknown arity and types */ From 57018b40d31f74dd64177564c733c5176b798dbf Mon Sep 17 00:00:00 2001 From: mzcu Date: Tue, 19 Oct 2021 08:45:41 +0200 Subject: [PATCH 0734/1244] Update canthrow.md Fix typo --- docs/docs/reference/experimental/canthrow.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/reference/experimental/canthrow.md b/docs/docs/reference/experimental/canthrow.md index 8233627bf27b..aaf637b06806 100644 --- a/docs/docs/reference/experimental/canthrow.md +++ b/docs/docs/reference/experimental/canthrow.md @@ -54,7 +54,7 @@ This assumes a type `A throws E` to indicate computations of type `A` that can t But there is a way to avoid the ceremony. Instead of concentrating on possible _effects_ such as "this code might throw an exception", concentrate on _capabilities_ such as "this code needs the capability to throw an exception". From a standpoint of expressiveness this is quite similar. But capabilities can be expressed as parameters whereas traditionally effects are expressed as some addition to result values. It turns out that this can make a big difference! -## The CanThrow Cabability +## The CanThrow Capability In the _effects as capabilities_ model, an effect is expressed as an (implicit) parameter of a certain type. For exceptions we would expect parameters of type `CanThrow[E]` where `E` stands for the exception that can be thrown. Here is the definition of `CanThrow`: From a3e3bff8271f0ae55774659ccf7c4a82378f8706 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Mon, 11 Oct 2021 18:05:46 +0200 Subject: [PATCH 0735/1244] Remove the last occurrence of the legacy JSInterop internal API. Now, everything goes through the extension methods in JSSymUtils. --- .../dotty/tools/backend/sjs/JSCodeGen.scala | 3 +- .../dotty/tools/backend/sjs/JSInterop.scala | 74 ------------------- 2 files changed, 1 insertion(+), 76 deletions(-) delete mode 100644 compiler/src/dotty/tools/backend/sjs/JSInterop.scala diff --git a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala index 1f707bcd17d9..e27da4a1edf4 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala @@ -42,7 +42,6 @@ import org.scalajs.ir.Trees.OptimizerHints import dotty.tools.dotc.transform.sjs.JSSymUtils._ import JSEncoding._ -import JSInterop._ import ScopedVar.withScopedVars /** Main codegen for Scala.js IR. @@ -526,7 +525,7 @@ class JSCodeGen()(using genCtx: Context) { /* We add symbols that we have to expose here. This way we also * get inherited stuff that is implemented in this class. */ - dispatchMethodNames += jsNameOf(sym) + dispatchMethodNames += sym.jsName } } diff --git a/compiler/src/dotty/tools/backend/sjs/JSInterop.scala b/compiler/src/dotty/tools/backend/sjs/JSInterop.scala deleted file mode 100644 index c22af60bd179..000000000000 --- a/compiler/src/dotty/tools/backend/sjs/JSInterop.scala +++ /dev/null @@ -1,74 +0,0 @@ -package dotty.tools.backend.sjs - -import dotty.tools.dotc.core._ -import Contexts._ -import Flags._ -import Symbols._ -import NameOps._ -import StdNames._ -import Phases._ - -import dotty.tools.dotc.transform.sjs.JSSymUtils._ - -/** Management of the interoperability with JavaScript. - * - * This object only contains forwarders for extension methods in - * `transform.sjs.JSSymUtils`. They are kept to minimize changes in - * `JSCodeGen` in the short term, but it will eventually be removed. - */ -object JSInterop { - - /** Is this symbol a JavaScript type? */ - def isJSType(sym: Symbol)(using Context): Boolean = - sym.isJSType - - /** Should this symbol be translated into a JS getter? - * - * This is true for any parameterless method, i.e., defined without `()`. - * Unlike `SymDenotations.isGetter`, it applies to user-defined methods as - * much as *accessor* methods created for `val`s and `var`s. - */ - def isJSGetter(sym: Symbol)(using Context): Boolean = - sym.isJSGetter - - /** Should this symbol be translated into a JS setter? - * - * This is true for any method whose name ends in `_=`. - * Unlike `SymDenotations.isGetter`, it applies to user-defined methods as - * much as *accessor* methods created for `var`s. - */ - def isJSSetter(sym: Symbol)(using Context): Boolean = - sym.isJSSetter - - /** Should this symbol be translated into a JS bracket access? - * - * This is true for methods annotated with `@JSBracketAccess`. - */ - def isJSBracketAccess(sym: Symbol)(using Context): Boolean = - sym.isJSBracketAccess - - /** Should this symbol be translated into a JS bracket call? - * - * This is true for methods annotated with `@JSBracketCall`. - */ - def isJSBracketCall(sym: Symbol)(using Context): Boolean = - sym.isJSBracketCall - - /** Is this symbol a default param accessor for a JS method? - * - * For default param accessors of *constructors*, we need to test whether - * the companion *class* of the owner is a JS type; not whether the owner - * is a JS type. - */ - def isJSDefaultParam(sym: Symbol)(using Context): Boolean = - sym.isJSDefaultParam - - /** Gets the unqualified JS name of a symbol. - * - * If it is not explicitly specified with an `@JSName` annotation, the - * JS name is inferred from the Scala name. - */ - def jsNameOf(sym: Symbol)(using Context): JSName = - sym.jsName - -} From 2bf6c608e3a0837657ad3b771ba49538e3c2e2ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Mon, 11 Oct 2021 18:20:55 +0200 Subject: [PATCH 0736/1244] Scala.js: Correctly identify default accessors of native JS def params. Previously, we tested whether the default accessor itself had the `@js.native` annotation. That is however never the case. Instead, we now test whether the associated method has the annotation. We still emit the *definitions* of those default accessors, even though that they are never called anymore, because of backward binary compatibility. If we stopped emitting them, a library compiled with a newer Scala.js might not link anymore against an application built with a previous Scala.js. This is a forward port of https://github.com/scala-js/scala-js/commit/7e998b40f7ad5933233aafee6d7cb628aab7f97d --- .../dotty/tools/backend/sjs/JSCodeGen.scala | 67 ++++++++++++++++++- .../tools/dotc/transform/sjs/JSSymUtils.scala | 20 ------ 2 files changed, 66 insertions(+), 21 deletions(-) diff --git a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala index e27da4a1edf4..7b1ff2d4738b 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala @@ -2007,8 +2007,46 @@ class JSCodeGen()(using genCtx: Context) { val args = tree.args val sym = tree.fun.symbol + /* Is the method a JS default accessor, which should become an + * `UndefinedParam` rather than being compiled normally. + * + * This is true iff one of the following conditions apply: + * - It is a constructor default param for the constructor of a JS class. + * - It is a default param of an instance method of a native JS type. + * - It is a default param of an instance method of a non-native JS type + * and the attached method is exposed. + * - It is a default param for a native JS def. + */ + def isJSDefaultParam: Boolean = { + sym.name.is(DefaultGetterName) && { + val info = new DefaultParamInfo(sym) + if (info.isForConstructor) { + /* This is a default accessor for a constructor parameter. Check + * whether the attached constructor is a JS constructor, which is + * the case iff the linked class is a JS type. + */ + info.constructorOwner.isJSType + } else { + if (sym.owner.isJSType) { + /* The default accessor is in a JS type. It is a JS default + * param iff the enclosing class is native or the attached method + * is exposed. + */ + !sym.owner.isNonNativeJSClass || info.attachedMethod.isJSExposed + } else { + /* The default accessor is in a Scala type. It is a JS default + * param iff the attached method is a native JS def. This can + * only happen if the owner is a module class, which we test + * first as a fast way out. + */ + sym.owner.is(ModuleClass) && info.attachedMethod.hasAnnotation(jsdefn.JSNativeAnnot) + } + } + } + } + tree.fun match { - case _ if sym.isJSDefaultParam => + case _ if isJSDefaultParam => js.Transient(UndefinedParam) case Select(Super(_, _), _) => @@ -4578,4 +4616,31 @@ object JSCodeGen { out.print("") } + /** Info about a default param accessor. + * + * The method must have a default getter name for this class to make sense. + */ + private class DefaultParamInfo(sym: Symbol)(using Context) { + private val methodName = sym.name.exclude(DefaultGetterName) + + def isForConstructor: Boolean = methodName == nme.CONSTRUCTOR + + /** When `isForConstructor` is true, returns the owner of the attached + * constructor. + */ + def constructorOwner: Symbol = sym.owner.linkedClass + + /** When `isForConstructor` is false, returns the method attached to the + * specified default accessor. + */ + def attachedMethod: Symbol = { + // If there are overloads, we need to find the one that has default params. + val overloads = sym.owner.info.decl(methodName) + if (!overloads.isOverloaded) + overloads.symbol + else + overloads.suchThat(_.is(HasDefaultParams)).symbol + } + } + } diff --git a/compiler/src/dotty/tools/dotc/transform/sjs/JSSymUtils.scala b/compiler/src/dotty/tools/dotc/transform/sjs/JSSymUtils.scala index f718d68e9588..58d93703ffc2 100644 --- a/compiler/src/dotty/tools/dotc/transform/sjs/JSSymUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/sjs/JSSymUtils.scala @@ -156,26 +156,6 @@ object JSSymUtils { def isJSBracketCall(using Context): Boolean = sym.hasAnnotation(jsdefn.JSBracketCallAnnot) - /** Is this symbol a default param accessor for a JS method? - * - * For default param accessors of *constructors*, we need to test whether - * the companion *class* of the owner is a JS type; not whether the owner - * is a JS type. - */ - def isJSDefaultParam(using Context): Boolean = { - sym.name.is(DefaultGetterName) && { - val owner = sym.owner - val methName = sym.name.exclude(DefaultGetterName) - if (methName == nme.CONSTRUCTOR) { - owner.linkedClass.isJSType - } else { - def isAttachedMethodExposed: Boolean = - owner.info.decl(methName).hasAltWith(_.symbol.isJSExposed) - owner.isJSType && (!owner.isNonNativeJSClass || isAttachedMethodExposed) - } - } - } - /** Is this symbol a default param accessor for the constructor of a native JS class? */ def isJSNativeCtorDefaultParam(using Context): Boolean = { sym.name.is(DefaultGetterName) From b1411e05f88f29c9516d72032ec547181994f9f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Mon, 11 Oct 2021 18:26:59 +0200 Subject: [PATCH 0737/1244] Scala.js: Allow default params of JS native defs to be `= js.native`. The default accessors matching that property are not emitted anymore. This is similar to how default accessors for JS native constructors are not emitted. Unfortunately, for backward binary compatibility reasons, we must still emit default accessors of JS native defs that are anything else than `= js.native`. Until Scala.js 1.7.0, those default accessors would actually be referenced by calling code (see https://github.com/scala-js/scala-js/issues/4554), so removing them now would create dangling references. This is a forward port of https://github.com/scala-js/scala-js/commit/e01dc1adcbc982860ff2248a3ae88901e95fca92 --- .../dotty/tools/backend/sjs/JSCodeGen.scala | 55 ++++++++++++++++++- .../tools/dotc/transform/sjs/JSSymUtils.scala | 7 --- 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala index 7b1ff2d4738b..5d9646e239e6 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala @@ -1402,6 +1402,53 @@ class JSCodeGen()(using genCtx: Context) { val vparamss = dd.termParamss val rhs = dd.rhs + /* Is this method a default accessor that should be ignored? + * + * This is the case iff one of the following applies: + * - It is a constructor default accessor and the linked class is a + * native JS class. + * - It is a default accessor for a native JS def, but with the caveat + * that its rhs must be `js.native` because of #4553. + * + * Both of those conditions can only happen if the default accessor is in + * a module class, so we use that as a fast way out. (But omitting that + * condition would not change the result.) + * + * This is different than `isJSDefaultParam` in `genApply`: we do not + * ignore default accessors of *non-native* JS types. Neither for + * constructor default accessor nor regular default accessors. We also + * do not need to worry about non-constructor members of native JS types, + * since for those, the entire member list is ignored in `genJSClassData`. + */ + def isIgnorableDefaultParam: Boolean = { + sym.name.is(DefaultGetterName) && sym.owner.is(ModuleClass) && { + val info = new DefaultParamInfo(sym) + if (info.isForConstructor) { + /* This is a default accessor for a constructor parameter. Check + * whether the attached constructor is a native JS constructor, + * which is the case iff the linked class is a native JS type. + */ + info.constructorOwner.hasAnnotation(jsdefn.JSNativeAnnot) + } else { + /* #4553 We need to ignore default accessors for JS native defs. + * However, because Scala.js <= 1.7.0 actually emitted code calling + * those accessors, we must keep default accessors that would + * compile. The only accessors we can actually get rid of are those + * that are `= js.native`. + */ + !sym.owner.isJSType && + info.attachedMethod.hasAnnotation(jsdefn.JSNativeAnnot) && { + dd.rhs match { + case MaybeAsInstanceOf(Apply(fun, _)) => + fun.symbol == jsdefn.JSPackage_native + case _ => + false + } + } + } + } + } + withPerMethodBodyState(sym) { assert(vparamss.isEmpty || vparamss.tail.isEmpty, "Malformed parameter list: " + vparamss) @@ -1421,7 +1468,7 @@ class JSCodeGen()(using genCtx: Context) { Some(js.MethodDef(js.MemberFlags.empty, methodName, originalName, jsParams, toIRType(patchedResultType(sym)), None)( OptimizerHints.empty, None)) - } else if (sym.isJSNativeCtorDefaultParam) { + } else if (isIgnorableDefaultParam) { // #11592 None } else if (sym.is(Bridge) && sym.name.is(DefaultGetterName) && currentClassSym.isNonNativeJSClass) { @@ -2016,6 +2063,12 @@ class JSCodeGen()(using genCtx: Context) { * - It is a default param of an instance method of a non-native JS type * and the attached method is exposed. * - It is a default param for a native JS def. + * + * This is different than `isIgnorableDefaultParam` in + * `genMethodWithCurrentLocalNameScope`: we include here the default + * accessors of *non-native* JS types (unless the corresponding methods are + * not exposed). We also need to handle non-constructor members of native + * JS types. */ def isJSDefaultParam: Boolean = { sym.name.is(DefaultGetterName) && { diff --git a/compiler/src/dotty/tools/dotc/transform/sjs/JSSymUtils.scala b/compiler/src/dotty/tools/dotc/transform/sjs/JSSymUtils.scala index 58d93703ffc2..a78adaff6522 100644 --- a/compiler/src/dotty/tools/dotc/transform/sjs/JSSymUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/sjs/JSSymUtils.scala @@ -156,13 +156,6 @@ object JSSymUtils { def isJSBracketCall(using Context): Boolean = sym.hasAnnotation(jsdefn.JSBracketCallAnnot) - /** Is this symbol a default param accessor for the constructor of a native JS class? */ - def isJSNativeCtorDefaultParam(using Context): Boolean = { - sym.name.is(DefaultGetterName) - && sym.name.exclude(DefaultGetterName) == nme.CONSTRUCTOR - && sym.owner.linkedClass.hasAnnotation(jsdefn.JSNativeAnnot) - } - def jsCallingConvention(using Context): JSCallingConvention = JSCallingConvention.of(sym) From dcb3bfe8e75c22512c5129128bf9a3bf5c4f4db9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Tue, 12 Oct 2021 17:47:00 +0200 Subject: [PATCH 0738/1244] Scala.js: Do not emit static forwarders for native JS defs. Nor for their default param accessors. This is a forward port of https://github.com/scala-js/scala-js/commit/a95f3f6ab4d844fe44ba601a57335e748f1d07d2 --- .../src/dotty/tools/backend/sjs/JSCodeGen.scala | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala index 5d9646e239e6..53885ba523ec 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala @@ -789,7 +789,21 @@ class JSCodeGen()(using genCtx: Context) { def isExcluded(m: Symbol): Boolean = { def hasAccessBoundary = m.accessBoundary(defn.RootClass) ne defn.RootClass - m.is(Deferred) || m.isConstructor || hasAccessBoundary || (m.owner eq defn.ObjectClass) + + def isOfJLObject: Boolean = m.owner eq defn.ObjectClass + + def isDefaultParamOfJSNativeDef: Boolean = { + m.name.is(DefaultGetterName) && { + val info = new DefaultParamInfo(m) + !info.isForConstructor && info.attachedMethod.hasAnnotation(jsdefn.JSNativeAnnot) + } + } + + m.is(Deferred) + || m.isConstructor + || hasAccessBoundary + || isOfJLObject + || m.hasAnnotation(jsdefn.JSNativeAnnot) || isDefaultParamOfJSNativeDef // #4557 } val forwarders = for { From b41b4cb5b66951059f0062e627de2d1eeb2053dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Tue, 12 Oct 2021 17:47:45 +0200 Subject: [PATCH 0739/1244] Upgrade to Scala.js 1.7.1. --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index 861d9491e13e..4e70c7f3122a 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -2,7 +2,7 @@ // // e.g. addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.1.0") -addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.7.0") +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.7.1") addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.6") From 1a2892fc4cb142be4076b93a919da51a9972e446 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 15 Oct 2021 19:40:22 +0200 Subject: [PATCH 0740/1244] Change order of proxy evaluation when inlining Fixes #13747 --- .../src/dotty/tools/dotc/typer/Inliner.scala | 55 ++++++++++++------- tests/run/i13747.scala | 17 ++++++ 2 files changed, 52 insertions(+), 20 deletions(-) create mode 100644 tests/run/i13747.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index 9bd293400d65..b4264dee6e64 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -37,6 +37,8 @@ import quoted.QuoteUtils object Inliner { import tpd._ + private type DefBuffer = mutable.ListBuffer[ValOrDefDef] + /** `sym` is an inline method with a known body to inline. */ def hasBodyToInline(sym: SymDenotation)(using Context): Boolean = @@ -413,7 +415,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { private val methPart = funPart(call) private val callTypeArgs = typeArgss(call).flatten - private val rawCallValueArgss = termArgss(call) + private val callValueArgss = termArgss(call) private val inlinedMethod = methPart.symbol private val inlineCallPrefix = qualifier(methPart).orElse(This(inlinedMethod.enclosingClass.asClass)) @@ -465,14 +467,14 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { /** A binding for the parameter of an inline method. This is a `val` def for * by-value parameters and a `def` def for by-name parameters. `val` defs inherit * inline annotations from their parameters. The generated `def` is appended - * to `bindingsBuf`. + * to `buf`. * @param name the name of the parameter * @param formal the type of the parameter * @param arg the argument corresponding to the parameter - * @param bindingsBuf the buffer to which the definition should be appended + * @param buf the buffer to which the definition should be appended */ private def paramBindingDef(name: Name, formal: Type, arg0: Tree, - bindingsBuf: mutable.ListBuffer[ValOrDefDef])(using Context): ValOrDefDef = { + buf: DefBuffer)(using Context): ValOrDefDef = { val isByName = formal.dealias.isInstanceOf[ExprType] val arg = arg0 match { case Typed(arg1, tpt) if tpt.tpe.isRepeatedParam && arg1.tpe.derivesFrom(defn.ArrayClass) => @@ -501,23 +503,25 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { else ValDef(boundSym, newArg) }.withSpan(boundSym.span) inlining.println(i"parameter binding: $binding, $argIsBottom") - bindingsBuf += binding + buf += binding binding } - /** Populate `paramBinding` and `bindingsBuf` by matching parameters with + /** Populate `paramBinding` and `buf` by matching parameters with * corresponding arguments. `bindingbuf` will be further extended later by * proxies to this-references. Issue an error if some arguments are missing. */ private def computeParamBindings( - tp: Type, targs: List[Tree], argss: List[List[Tree]], formalss: List[List[Type]]): Boolean = + tp: Type, targs: List[Tree], + argss: List[List[Tree]], formalss: List[List[Type]], + buf: DefBuffer): Boolean = tp match case tp: PolyType => tp.paramNames.lazyZip(targs).foreach { (name, arg) => paramSpan(name) = arg.span paramBinding(name) = arg.tpe.stripTypeVar } - computeParamBindings(tp.resultType, targs.drop(tp.paramNames.length), argss, formalss) + computeParamBindings(tp.resultType, targs.drop(tp.paramNames.length), argss, formalss, buf) case tp: MethodType => if argss.isEmpty then report.error(i"missing arguments for inline method $inlinedMethod", call.srcPos) @@ -529,9 +533,9 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { case _: SingletonType if isIdempotentPath(arg) => arg.tpe case _ => - paramBindingDef(name, formal, arg, bindingsBuf).symbol.termRef + paramBindingDef(name, formal, arg, buf).symbol.termRef } - computeParamBindings(tp.resultType, targs, argss.tail, formalss.tail) + computeParamBindings(tp.resultType, targs, argss.tail, formalss.tail, buf) case _ => assert(targs.isEmpty) assert(argss.isEmpty) @@ -810,7 +814,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { def inlined(sourcePos: SrcPos): Tree = { // Special handling of `requireConst` and `codeOf` - rawCallValueArgss match + callValueArgss match case (arg :: Nil) :: Nil => if inlinedMethod == defn.Compiletime_requireConst then arg match @@ -860,17 +864,25 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { case TypeApply(fn, _) => paramTypess(fn, acc) case _ => acc - val callValueArgss = rawCallValueArgss.nestedMapConserve(mapOpaquesInValueArg) + val paramBindings = + val mappedCallValueArgss = callValueArgss.nestedMapConserve(mapOpaquesInValueArg) + if mappedCallValueArgss ne callValueArgss then + inlining.println(i"mapped value args = ${mappedCallValueArgss.flatten}%, %") - if callValueArgss ne rawCallValueArgss then - inlining.println(i"mapped value args = ${callValueArgss.flatten}%, %") + val paramBindingsBuf = new DefBuffer + // Compute bindings for all parameters, appending them to bindingsBuf + if !computeParamBindings( + inlinedMethod.info, callTypeArgs, + mappedCallValueArgss, paramTypess(call, Nil), + paramBindingsBuf) + then + return call - // Compute bindings for all parameters, appending them to bindingsBuf - if !computeParamBindings(inlinedMethod.info, callTypeArgs, callValueArgss, paramTypess(call, Nil)) then - return call + paramBindingsBuf.toList + end paramBindings // make sure prefix is executed if it is impure - if (!isIdempotentExpr(inlineCallPrefix)) registerType(inlinedMethod.owner.thisType) + if !isIdempotentExpr(inlineCallPrefix) then registerType(inlinedMethod.owner.thisType) // Register types of all leaves of inlined body so that the `paramProxy` and `thisProxy` maps are defined. rhsToInline.foreachSubTree(registerLeaf) @@ -878,6 +890,9 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { // Compute bindings for all this-proxies, appending them to bindingsBuf computeThisBindings() + // Parameter bindings come after this bindings, reflecting order of evaluation + bindingsBuf ++= paramBindings + val inlineTyper = new InlineTyper(ctx.reporter.errorCount) val inlineCtx = inlineContext(call).fresh.setTyper(inlineTyper).setNewScope @@ -1190,7 +1205,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { private object InlineableArg { lazy val paramProxies = paramProxy.values.toSet def unapply(tree: Trees.Ident[?])(using Context): Option[Tree] = { - def search(buf: mutable.ListBuffer[ValOrDefDef]) = buf.find(_.name == tree.name) + def search(buf: DefBuffer) = buf.find(_.name == tree.name) if (paramProxies.contains(tree.typeOpt)) search(bindingsBuf) match { case Some(bind: ValOrDefDef) if bind.symbol.is(Inline) => @@ -1229,7 +1244,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { cpy.Inlined(cl)(call, bindings, recur(expr)) case _ => ddef.tpe.widen match case mt: MethodType if ddef.paramss.head.length == args.length => - val bindingsBuf = new mutable.ListBuffer[ValOrDefDef] + val bindingsBuf = new DefBuffer val argSyms = mt.paramNames.lazyZip(mt.paramInfos).lazyZip(args).map { (name, paramtp, arg) => arg.tpe.dealias match { case ref @ TermRef(NoPrefix, _) => ref.symbol diff --git a/tests/run/i13747.scala b/tests/run/i13747.scala new file mode 100644 index 000000000000..2167523bd754 --- /dev/null +++ b/tests/run/i13747.scala @@ -0,0 +1,17 @@ +var res = "" +trait Bar: + def +(that: Bar): Bar = new Plus(this, that) + transparent inline def -(that: Bar): Bar = new Minus(this, that) + +class LHS extends Bar {res += "LHS "} +class RHS extends Bar {res += "RHS "} + +class Plus(lhs: Bar, rhs: Bar) extends Bar {res += "op"} +class Minus(lhs: Bar, rhs: Bar) extends Bar {res += "op"} + +@main def Test = + val pls = new LHS + new RHS + val plsRes = res + res = "" + val min = new LHS - new RHS + assert(plsRes == res) \ No newline at end of file From 94a24c21f25611329a16c91321c5f05a12fb6604 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 20 Oct 2021 12:20:58 +0200 Subject: [PATCH 0741/1244] Add missing `@experimental` in `Tuples` --- library/src/scala/runtime/Tuples.scala | 4 ++++ project/MiMaFilters.scala | 1 + 2 files changed, 5 insertions(+) diff --git a/library/src/scala/runtime/Tuples.scala b/library/src/scala/runtime/Tuples.scala index e5018cce47a6..1c81782acecb 100644 --- a/library/src/scala/runtime/Tuples.scala +++ b/library/src/scala/runtime/Tuples.scala @@ -1,5 +1,7 @@ package scala.runtime +import scala.annotation.experimental + object Tuples { inline val MaxSpecialized = 22 @@ -422,11 +424,13 @@ object Tuples { } } + @experimental def init(self: NonEmptyTuple): Tuple = (self: Any) match { case xxl: TupleXXL => xxlInit(xxl) case _ => specialCaseInit(self) } + @experimental def last(self: NonEmptyTuple): Any = (self: Any) match { case self: Product => self.productElement(self.productArity - 1) } diff --git a/project/MiMaFilters.scala b/project/MiMaFilters.scala index 0f8dbfa896c0..9fe7da22fb2a 100644 --- a/project/MiMaFilters.scala +++ b/project/MiMaFilters.scala @@ -4,6 +4,7 @@ import com.typesafe.tools.mima.core.ProblemFilters._ object MiMaFilters { val Library: Seq[ProblemFilter] = Seq( + // Experimental APIs that can be added in 3.2.0 ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.init"), ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.last") ) From f3ea6fd9133b6a36efb7c8a0b42e26f36562d7cc Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 14 Oct 2021 18:01:36 +0200 Subject: [PATCH 0742/1244] Widen qualifier skolems Fixes #13422 --- .../src/scala/quoted/runtime/impl/QuotesImpl.scala | 2 +- tests/pos-macros/i13422/Macro_1.scala | 9 +++++++++ tests/pos-macros/i13422/Test_2.scala | 12 ++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 tests/pos-macros/i13422/Macro_1.scala create mode 100644 tests/pos-macros/i13422/Test_2.scala diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index d64ecb1d33e5..ab651408a0c4 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -1777,7 +1777,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler given NamedTypeMethods: NamedTypeMethods with extension (self: NamedType) - def qualifier: TypeRepr = self.prefix + def qualifier: TypeRepr = self.prefix.widenSkolem def name: String = self.name.toString end extension end NamedTypeMethods diff --git a/tests/pos-macros/i13422/Macro_1.scala b/tests/pos-macros/i13422/Macro_1.scala new file mode 100644 index 000000000000..a141049523ff --- /dev/null +++ b/tests/pos-macros/i13422/Macro_1.scala @@ -0,0 +1,9 @@ +import scala.quoted._ + +inline def rule(inline r: Any): Unit = ${ ruleImpl('r) } + +def ruleImpl(r: Expr[Any])(using Quotes): Expr[Unit] = { + import quotes.reflect.* + r.asTerm.show + '{} +} diff --git a/tests/pos-macros/i13422/Test_2.scala b/tests/pos-macros/i13422/Test_2.scala new file mode 100644 index 000000000000..f6595825516a --- /dev/null +++ b/tests/pos-macros/i13422/Test_2.scala @@ -0,0 +1,12 @@ +def test = rule { + foo(bar(baz)) +} + +def foo[I](r: I): Nothing = ??? + +def bar(i: Baz): i.Out = ??? + +sealed trait Baz: + type Out = Nothing match { case Nothing => Nothing } + +def baz: Baz = ??? From 09eeb99c902bf22255b909a8c3954aac9257c8c6 Mon Sep 17 00:00:00 2001 From: danicheg Date: Thu, 21 Oct 2021 13:13:25 +0300 Subject: [PATCH 0743/1244] Add append operator to Tuple --- library/src/scala/Tuple.scala | 12 ++++ library/src/scala/runtime/Tuples.scala | 76 +++++++++++++++++++++++ project/MiMaFilters.scala | 3 +- tests/run-deep-subtype/Tuple-append.check | 76 +++++++++++++++++++++++ tests/run-deep-subtype/Tuple-append.scala | 65 +++++++++++++++++++ 5 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 tests/run-deep-subtype/Tuple-append.check create mode 100644 tests/run-deep-subtype/Tuple-append.scala diff --git a/library/src/scala/Tuple.scala b/library/src/scala/Tuple.scala index 784170c524ae..06d258e3e503 100644 --- a/library/src/scala/Tuple.scala +++ b/library/src/scala/Tuple.scala @@ -21,6 +21,11 @@ sealed trait Tuple extends Product { inline def toIArray: IArray[Object] = runtime.Tuples.toIArray(this) + /** Return a copy of `this` tuple with an element appended */ + @experimental + inline def :* [This >: this.type <: Tuple, L] (x: L): Append[This, L] = + runtime.Tuples.append(x, this).asInstanceOf[Append[This, L]] + /** Return a new tuple by prepending the element to `this` tuple. * This operation is O(this.size) */ @@ -78,6 +83,13 @@ sealed trait Tuple extends Product { object Tuple { + /** Type of a tuple with an element appended */ + @experimental + type Append[X <: Tuple, Y] <: Tuple = X match { + case EmptyTuple => Y *: EmptyTuple + case x *: xs => x *: Append[xs, Y] + } + /** Type of the head of a tuple */ type Head[X <: NonEmptyTuple] = X match { case x *: _ => x diff --git a/library/src/scala/runtime/Tuples.scala b/library/src/scala/runtime/Tuples.scala index 1c81782acecb..bfb863bcc0f0 100644 --- a/library/src/scala/runtime/Tuples.scala +++ b/library/src/scala/runtime/Tuples.scala @@ -357,6 +357,82 @@ object Tuples { case _ => specialCaseTail(self) } + // Append for TupleXXL + private def xxlAppend(x: Any, xxl: TupleXXL): TupleXXL = { + val arr = new Array[Object](xxl.productArity + 1) + arr(xxl.productArity) = x.asInstanceOf[Object] + System.arraycopy(xxl.elems, 0, arr, 0, xxl.productArity) + TupleXXL.fromIArray(arr.asInstanceOf[IArray[Object]]) + } + + // Append for Tuple1 to Tuple22 + private def specialCaseAppend(x: Any, self: Tuple): Tuple = { + (self: Any) match { + case EmptyTuple => + Tuple1(x) + case self: Tuple1[_] => + Tuple2(self._1, x) + case self: Tuple2[_, _] => + Tuple3(self._1, self._2, x) + case self: Tuple3[_, _, _] => + Tuple4(self._1, self._2, self._3, x) + case self: Tuple4[_, _, _, _] => + Tuple5(self._1, self._2, self._3, self._4, x) + case self: Tuple5[_, _, _, _, _] => + Tuple6(self._1, self._2, self._3, self._4, self._5, x) + case self: Tuple6[_, _, _, _, _, _] => + Tuple7(self._1, self._2, self._3, self._4, self._5, self._6, x) + case self: Tuple7[_, _, _, _, _, _, _] => + Tuple8(self._1, self._2, self._3, self._4, self._5, self._6, self._7, x) + case self: Tuple8[_, _, _, _, _, _, _, _] => + Tuple9(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, x) + case self: Tuple9[_, _, _, _, _, _, _, _, _] => + Tuple10(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, x) + case self: Tuple10[_, _, _, _, _, _, _, _, _, _] => + Tuple11(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, x) + case self: Tuple11[_, _, _, _, _, _, _, _, _, _, _] => + Tuple12(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, x) + case self: Tuple12[_, _, _, _, _, _, _, _, _, _, _, _] => + Tuple13(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, x) + case self: Tuple13[_, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple14(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, x) + case self: Tuple14[_, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple15(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, self._14, x) + case self: Tuple15[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple16(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, self._14, self._15, x) + case self: Tuple16[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple17(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, self._14, self._15, self._16, x) + case self: Tuple17[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple18(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, self._14, self._15, self._16, self._17, x) + case self: Tuple18[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple19(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, self._14, self._15, self._16, self._17, self._18, x) + case self: Tuple19[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple20(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, self._14, self._15, self._16, self._17, self._18, self._19, x) + case self: Tuple20[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple21(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, self._14, self._15, self._16, self._17, self._18, self._19, self._20, x) + case self: Tuple21[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple22(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, self._14, self._15, self._16, self._17, self._18, self._19, self._20, self._21, x) + case self: Tuple22[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + val arr: Array[Object] = Array( + self._1.asInstanceOf[Object], self._2.asInstanceOf[Object], + self._3.asInstanceOf[Object], self._4.asInstanceOf[Object], self._5.asInstanceOf[Object], + self._6.asInstanceOf[Object], self._7.asInstanceOf[Object], self._8.asInstanceOf[Object], + self._9.asInstanceOf[Object], self._10.asInstanceOf[Object], self._11.asInstanceOf[Object], + self._12.asInstanceOf[Object], self._13.asInstanceOf[Object], self._14.asInstanceOf[Object], + self._15.asInstanceOf[Object], self._16.asInstanceOf[Object], self._17.asInstanceOf[Object], + self._18.asInstanceOf[Object], self._19.asInstanceOf[Object], self._20.asInstanceOf[Object], + self._21.asInstanceOf[Object], self._22.asInstanceOf[Object], x.asInstanceOf[Object] + ) + TupleXXL.fromIArray(arr.asInstanceOf[IArray[Object]]).asInstanceOf[Tuple] + } + } + + @experimental + def append(x: Any, self: Tuple): Tuple = (self: Any) match { + case xxl: TupleXXL => xxlAppend(x, xxl).asInstanceOf[Tuple] + case _ => specialCaseAppend(x, self) + } + // Init for TupleXXL private def xxlInit(xxl: TupleXXL): Tuple = { if (xxl.productArity == 23) { diff --git a/project/MiMaFilters.scala b/project/MiMaFilters.scala index 9fe7da22fb2a..e37bce1b3cf9 100644 --- a/project/MiMaFilters.scala +++ b/project/MiMaFilters.scala @@ -6,6 +6,7 @@ object MiMaFilters { val Library: Seq[ProblemFilter] = Seq( // Experimental APIs that can be added in 3.2.0 ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.init"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.last") + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.last"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.append") ) } diff --git a/tests/run-deep-subtype/Tuple-append.check b/tests/run-deep-subtype/Tuple-append.check new file mode 100644 index 000000000000..96c717f2aef0 --- /dev/null +++ b/tests/run-deep-subtype/Tuple-append.check @@ -0,0 +1,76 @@ +(0) +(0,1) +(0,1,2) +(0,1,2,3) +(0,1,2,3,4) +(0,1,2,3,4,5) +(0,1,2,3,4,5,6) +(0,1,2,3,4,5,6,7) +(0,1,2,3,4,5,6,7,8) +(0,1,2,3,4,5,6,7,8,9) +(0,1,2,3,4,5,6,7,8,9,10) +(0,1,2,3,4,5,6,7,8,9,10,11) +(0,1,2,3,4,5,6,7,8,9,10,11,12) +(0,1,2,3,4,5,6,7,8,9,10,11,12,13) +(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14) +(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15) +(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16) +(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17) +(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18) +(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19) +(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20) +(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21) +(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22) +(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23) +(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24) +(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25) +(1) +(1,2) +(1,2,3) +(1,2,3,4) +(1,2,3,4,5) +(1,2,3,4,5,6) +(1,2,3,4,5,6,7) +(1,2,3,4,5,6,7,8) +(1,2,3,4,5,6,7,8,9) +(1,2,3,4,5,6,7,8,9,10) +(1,2,3,4,5,6,7,8,9,10,11) +(1,2,3,4,5,6,7,8,9,10,11,12) +(1,2,3,4,5,6,7,8,9,10,11,12,13) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25) +(1) +(1,2) +(1,2,3) +(1,2,3,4) +(1,2,3,4,5) +(1,2,3,4,5,6) +(1,2,3,4,5,6,7) +(1,2,3,4,5,6,7,8) +(1,2,3,4,5,6,7,8,9) +(1,2,3,4,5,6,7,8,9,10) +(1,2,3,4,5,6,7,8,9,10,11) +(1,2,3,4,5,6,7,8,9,10,11,12) +(1,2,3,4,5,6,7,8,9,10,11,12,13) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25) diff --git a/tests/run-deep-subtype/Tuple-append.scala b/tests/run-deep-subtype/Tuple-append.scala new file mode 100644 index 000000000000..d913b4c98e1d --- /dev/null +++ b/tests/run-deep-subtype/Tuple-append.scala @@ -0,0 +1,65 @@ +import scala.reflect.ClassTag + +object Test { + def main(args: Array[String]): Unit = { + def testArray[T: ClassTag](n: Int, elem: Int => T): Unit = { + val t: Tuple = Tuple.fromArray(Array.tabulate(n)(elem)) + println(t :* n) + } + + for (i <- 0 to 25) + testArray(i, j => j) + + println(Tuple() :* 1) + println(Tuple1(1) :* 2) + println((1, 2) :* 3) + println((1, 2, 3) :* 4) + println((1, 2, 3, 4) :* 5) + println((1, 2, 3, 4, 5) :* 6) + println((1, 2, 3, 4, 5, 6) :* 7) + println((1, 2, 3, 4, 5, 6, 7) :* 8) + println((1, 2, 3, 4, 5, 6, 7, 8) :* 9) + println((1, 2, 3, 4, 5, 6, 7, 8, 9) :* 10) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10) :* 11) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) :* 12) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) :* 13) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13) :* 14) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14) :* 15) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) :* 16) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) :* 17) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17) :* 18) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18) :* 19) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19) :* 20) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20) :* 21) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21) :* 22) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22) :* 23) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23) :* 24) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24) :* 25) + + println(EmptyTuple :* 1) + println((1 *: Tuple()) :* 2) + println((1 *: 2 *: Tuple()) :* 3) + println((1 *: 2 *: 3 *: Tuple()) :* 4) + println((1 *: 2 *: 3 *: 4 *: Tuple()) :* 5) + println((1 *: 2 *: 3 *: 4 *: 5 *: Tuple()) :* 6) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: Tuple()) :* 7) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: Tuple()) :* 8) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: Tuple()) :* 9) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: Tuple()) :* 10) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: Tuple()) :* 11) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: Tuple()) :* 12) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: Tuple()) :* 13) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: Tuple()) :* 14) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: Tuple()) :* 15) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: Tuple()) :* 16) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: Tuple()) :* 17) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: Tuple()) :* 18) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: Tuple()) :* 19) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: Tuple()) :* 20) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: Tuple()) :* 21) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: 21 *: Tuple()) :* 22) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: 21 *: 22 *: Tuple()) :* 23) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: 21 *: 22 *: 23 *: Tuple()) :* 24) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: 21 *: 22 *: 23 *: 24 *: Tuple()) :* 25) + } +} From 5b65ef14dc91a3b60d3db7950016692fff4e0c33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Marks?= Date: Mon, 18 Oct 2021 14:11:21 +0200 Subject: [PATCH 0744/1244] Set reference and previous version to 3.1.0 --- project/Build.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project/Build.scala b/project/Build.scala index 65daf5ee280c..0bb061baae43 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -59,7 +59,7 @@ object DottyJSPlugin extends AutoPlugin { } object Build { - val referenceVersion = "3.1.0-RC1" + val referenceVersion = "3.1.0" val baseVersion = "3.1.1-RC1" @@ -77,7 +77,7 @@ object Build { * set to 3.1.3. If it is going to be 3.1.0, it must be set to the latest * 3.0.x release. */ - val previousDottyVersion = "3.1.0-RC3" + val previousDottyVersion = "3.1.0" object CompatMode { final val BinaryCompatible = 0 From 6d5fa645fc8fb14cf86b5e93c10dd283e68b7133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Marks?= Date: Mon, 18 Oct 2021 14:13:47 +0200 Subject: [PATCH 0745/1244] Set base version to 3.1.2-RC1 --- project/Build.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project/Build.scala b/project/Build.scala index 0bb061baae43..ff99753add6e 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -59,9 +59,9 @@ object DottyJSPlugin extends AutoPlugin { } object Build { - val referenceVersion = "3.1.0" + val referenceVersion = "3.1.1-RC1" - val baseVersion = "3.1.1-RC1" + val baseVersion = "3.1.2-RC1" // Versions used by the vscode extension to create a new project // This should be the latest published releases. From 65827f6561f11f32e33c437774f60cd910b532fc Mon Sep 17 00:00:00 2001 From: Gagandeep Kalra Date: Fri, 15 Oct 2021 01:17:42 +0800 Subject: [PATCH 0746/1244] fix #13011, error out infinite recursive lazy val MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tom Grigg Co-authored-by: Nicolas Stucki Co-authored-by: Timothée Andres --- .../dotc/transform/CheckLoopingImplicits.scala | 16 +++++++++++----- .../neg-custom-args/fatal-warnings/i13542.scala | 2 +- tests/neg/i13011.scala | 17 +++++++++++++++++ 3 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 tests/neg/i13011.scala diff --git a/compiler/src/dotty/tools/dotc/transform/CheckLoopingImplicits.scala b/compiler/src/dotty/tools/dotc/transform/CheckLoopingImplicits.scala index 5f8a8ee054f6..4818153e00e6 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckLoopingImplicits.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckLoopingImplicits.scala @@ -20,7 +20,13 @@ class CheckLoopingImplicits extends MiniPhase: override def phaseName: String = CheckLoopingImplicits.name - override def transformDefDef(mdef: DefDef)(using Context): DefDef = + override def transformValDef(mdef: ValDef)(using Context): Tree = + transform(mdef) + + override def transformDefDef(mdef: DefDef)(using Context): Tree = + transform(mdef) + + def transform(mdef: ValOrDefDef)(using Context): Tree = val sym = mdef.symbol def checkNotSelfRef(t: RefTree) = @@ -70,12 +76,12 @@ class CheckLoopingImplicits extends MiniPhase: checkNotLooping(finalizer) case SeqLiteral(elems, _) => elems.foreach(checkNotLooping) - case t: ValDef => - if !t.symbol.is(Lazy) then checkNotLooping(t.rhs) + case t: ValDef => + checkNotLooping(t.rhs) case _ => - if sym.isOneOf(GivenOrImplicit) then + if sym.isOneOf(GivenOrImplicit | Lazy) then checkNotLooping(mdef.rhs) mdef - end transformDefDef + end transform end CheckLoopingImplicits \ No newline at end of file diff --git a/tests/neg-custom-args/fatal-warnings/i13542.scala b/tests/neg-custom-args/fatal-warnings/i13542.scala index 1c5fa4958c75..3da18c233583 100644 --- a/tests/neg-custom-args/fatal-warnings/i13542.scala +++ b/tests/neg-custom-args/fatal-warnings/i13542.scala @@ -40,7 +40,7 @@ val x5 = val x6 = implicit def barToFoo4(bar: Bar): Foo = - lazy val y = bar.toFoo // OK + lazy val y = bar.toFoo // error if false then y else ??? val foo: Foo = Bar(1) diff --git a/tests/neg/i13011.scala b/tests/neg/i13011.scala new file mode 100644 index 000000000000..97c626e574e9 --- /dev/null +++ b/tests/neg/i13011.scala @@ -0,0 +1,17 @@ +class i13011 { + lazy implicit val simple1: String = simple1 // error + def f: Unit = { + lazy val simple2: String = simple2 // error + } + + lazy val simple3: String = if true then this.simple3 else "a" // error + + lazy val simple4: String = identity(this.simple4) // error + + lazy val simple5: String = { // error + this.simple5 + "aa" + } + + lazy val simple6: Function0[Any] = () => this.simple6 // Ok +} From 876215b0363c9e057310b715b2448e01460294a2 Mon Sep 17 00:00:00 2001 From: Gagandeep Kalra Date: Fri, 15 Oct 2021 18:23:12 +0800 Subject: [PATCH 0747/1244] moved i13011 to neg-custom-args/fatal-warnings --- tests/{neg => neg-custom-args/fatal-warnings}/i13011.scala | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{neg => neg-custom-args/fatal-warnings}/i13011.scala (100%) diff --git a/tests/neg/i13011.scala b/tests/neg-custom-args/fatal-warnings/i13011.scala similarity index 100% rename from tests/neg/i13011.scala rename to tests/neg-custom-args/fatal-warnings/i13011.scala From cc81660d6fe3c6a4483831ec7acba4796bc85424 Mon Sep 17 00:00:00 2001 From: Gagandeep Kalra Date: Sat, 16 Oct 2021 00:12:04 +0800 Subject: [PATCH 0748/1244] fixed repl test --- compiler/test-resources/repl/10886 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/test-resources/repl/10886 b/compiler/test-resources/repl/10886 index 820187b0b33c..5d06f7995a13 100644 --- a/compiler/test-resources/repl/10886 +++ b/compiler/test-resources/repl/10886 @@ -3,7 +3,7 @@ scala> type Channel = "A" | "B" scala> type SelChannel[C <: Tuple] = C match { case x *: xs => x | SelChannel[xs] case _ => Nothing } -scala> lazy val a: SelChannel[("A", "B", "C")] = a +scala> lazy val a: SelChannel[("A", "B", "C")] = "A" lazy val a: "A" | ("B" | ("C" | Nothing)) scala>:type a From 09c275735a27a390d9f1f692542e44901560608d Mon Sep 17 00:00:00 2001 From: Gagandeep Kalra Date: Sun, 17 Oct 2021 20:56:09 +0800 Subject: [PATCH 0749/1244] added additonal check for boolean case --- tests/neg-custom-args/fatal-warnings/i13011.scala | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/neg-custom-args/fatal-warnings/i13011.scala b/tests/neg-custom-args/fatal-warnings/i13011.scala index 97c626e574e9..c4ea118b4627 100644 --- a/tests/neg-custom-args/fatal-warnings/i13011.scala +++ b/tests/neg-custom-args/fatal-warnings/i13011.scala @@ -6,12 +6,16 @@ class i13011 { lazy val simple3: String = if true then this.simple3 else "a" // error - lazy val simple4: String = identity(this.simple4) // error + def firstDigitIsEven(n: Int): Boolean = if n % 10 == n then n % 2 == 0 else firstDigitIsEven(n / 10) + + lazy val simple4: String = if firstDigitIsEven(22) then this.simple4 else "a" // error + + lazy val simple5: String = identity(this.simple5) // error - lazy val simple5: String = { // error - this.simple5 + lazy val simple6: String = { // error + this.simple6 "aa" } - lazy val simple6: Function0[Any] = () => this.simple6 // Ok + lazy val simple7: Function0[Any] = () => this.simple7 // Ok } From 72ed9c8edcc190ad970bb130d06ab2a066c6d8b3 Mon Sep 17 00:00:00 2001 From: Gagandeep Kalra Date: Mon, 18 Oct 2021 17:14:06 +0800 Subject: [PATCH 0750/1244] fixed positive test case --- tests/neg-custom-args/fatal-warnings/i13011.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/neg-custom-args/fatal-warnings/i13011.scala b/tests/neg-custom-args/fatal-warnings/i13011.scala index c4ea118b4627..ae534394bf96 100644 --- a/tests/neg-custom-args/fatal-warnings/i13011.scala +++ b/tests/neg-custom-args/fatal-warnings/i13011.scala @@ -8,7 +8,7 @@ class i13011 { def firstDigitIsEven(n: Int): Boolean = if n % 10 == n then n % 2 == 0 else firstDigitIsEven(n / 10) - lazy val simple4: String = if firstDigitIsEven(22) then this.simple4 else "a" // error + lazy val simple4: String = if firstDigitIsEven(22) then this.simple4 else "a" // ok lazy val simple5: String = identity(this.simple5) // error From 5a162c7f4e3e6bf9cd6a83c235ac278dfb2aaec6 Mon Sep 17 00:00:00 2001 From: Matthieu Bovel Date: Thu, 21 Oct 2021 13:50:49 +0200 Subject: [PATCH 0751/1244] Allow passing any JMH option to scala3-bench --- bench/profiles/ci.yml | 30 ++++++------ bench/profiles/empty.yml | 6 +-- bench/profiles/exhaustivity.yml | 16 +++---- bench/profiles/implicits.yml | 8 ++-- bench/profiles/misc.yml | 4 +- bench/profiles/projects.yml | 4 +- bench/profiles/sbt.yml | 2 +- bench/profiles/tuples.yml | 10 ++-- bench/profiles/typing.yml | 2 +- bench/scripts/collection-vector.sh | 2 +- bench/scripts/compiler-cold.sh | 2 +- bench/scripts/compiler.sh | 2 +- bench/scripts/library-cold.sh | 2 +- bench/scripts/library.sh | 2 +- bench/src/main/scala/Benchmarks.scala | 66 ++++++++++++++++----------- 15 files changed, 86 insertions(+), 72 deletions(-) diff --git a/bench/profiles/ci.yml b/bench/profiles/ci.yml index 0571d509a286..96a4c1e10716 100644 --- a/bench/profiles/ci.yml +++ b/bench/profiles/ci.yml @@ -1,55 +1,55 @@ scripts: re2s: - - measure 1 1 1 $(find $PROG_HOME/tests/re2s/src -name *.scala) + - measure -wi 1 -i 1 -f 1 -- $(find $PROG_HOME/tests/re2s/src -name *.scala) implicit-cache: - - measure 1 1 1 $PROG_HOME/dotty/tests/bench/implicit_cache.scala + - measure -wi 1 -i 1 -f 1 -- $PROG_HOME/dotty/tests/bench/implicit_cache.scala implicit-cache-from-tasty: - source $PROG_HOME/dotty/bench/scripts/implicit-cache-from-tasty implicit-scope-loop: - - measure 1 1 1 $PROG_HOME/dotty/tests/bench/implicit-scope-loop.scala + - measure -wi 1 -i 1 -f 1 -- $PROG_HOME/dotty/tests/bench/implicit-scope-loop.scala i1535: - - measure 1 1 1 $PROG_HOME/dotty/tests/bench/i1535.scala + - measure -wi 1 -i 1 -f 1 -- $PROG_HOME/dotty/tests/bench/i1535.scala i1687: - - measure 1 1 1 $PROG_HOME/dotty/tests/bench/i1687.scala + - measure -wi 1 -i 1 -f 1 -- $PROG_HOME/dotty/tests/bench/i1687.scala empty-class: - - measure 1 1 1 $PROG_HOME/dotty/tests/bench/empty-class.scala + - measure -wi 1 -i 1 -f 1 -- $PROG_HOME/dotty/tests/bench/empty-class.scala empty-object: - - measure 1 1 1 $PROG_HOME/dotty/tests/bench/empty-object.scala + - measure -wi 1 -i 1 -f 1 -- $PROG_HOME/dotty/tests/bench/empty-object.scala empty-file: - - measure 1 1 1 $PROG_HOME/dotty/tests/bench/empty-file.scala + - measure -wi 1 -i 1 -f 1 -- $PROG_HOME/dotty/tests/bench/empty-file.scala patmatexhaust: - - measure 1 1 1 $PROG_HOME/dotty/tests/bench/patmatexhaust.scala + - measure -wi 1 -i 1 -f 1 -- $PROG_HOME/dotty/tests/bench/patmatexhaust.scala exhaustivity-I: - - measure 1 1 1 $PROG_HOME/dotty/tests/bench/exhaustivity-I.scala + - measure -wi 1 -i 1 -f 1 -- $PROG_HOME/dotty/tests/bench/exhaustivity-I.scala exhaustivity-S: - - measure 1 1 1 $PROG_HOME/dotty/tests/bench/exhaustivity-S.scala + - measure -wi 1 -i 1 -f 1 -- $PROG_HOME/dotty/tests/bench/exhaustivity-S.scala exhaustivity-T: - - measure 1 1 1 $PROG_HOME/dotty/tests/bench/exhaustivity-T.scala + - measure -wi 1 -i 1 -f 1 -- $PROG_HOME/dotty/tests/bench/exhaustivity-T.scala exhaustivity-V: - - measure 1 1 1 $PROG_HOME/dotty/tests/bench/exhaustivity-V.scala + - measure -wi 1 -i 1 -f 1 -- $PROG_HOME/dotty/tests/bench/exhaustivity-V.scala implicitNums: - - measure 1 1 1 $PROG_HOME/dotty/tests/bench/implicitNums.scala + - measure -wi 1 -i 1 -f 1 -- $PROG_HOME/dotty/tests/bench/implicitNums.scala implicitNums-from-tasty: - source $PROG_HOME/dotty/bench/scripts/implicitNums-from-tasty inductive-implicits: - - measure 1 1 1 $PROG_HOME/dotty/tests/bench/inductive-implicits.scala + - measure -wi 1 -i 1 -f 1 -- $PROG_HOME/dotty/tests/bench/inductive-implicits.scala scalap: - source $PROG_HOME/dotty/bench/scripts/scalap diff --git a/bench/profiles/empty.yml b/bench/profiles/empty.yml index ef878e07f50d..bdee3609fe8d 100644 --- a/bench/profiles/empty.yml +++ b/bench/profiles/empty.yml @@ -21,13 +21,13 @@ charts: scripts: empty-class: - - measure $PROG_HOME/dotty/tests/bench/empty-class.scala + - measure -- $PROG_HOME/dotty/tests/bench/empty-class.scala empty-object: - - measure $PROG_HOME/dotty/tests/bench/empty-object.scala + - measure -- $PROG_HOME/dotty/tests/bench/empty-object.scala empty-file: - - measure $PROG_HOME/dotty/tests/bench/empty-file.scala + - measure -- $PROG_HOME/dotty/tests/bench/empty-file.scala config: pr_base_url: "https://github.com/lampepfl/dotty/pull/" diff --git a/bench/profiles/exhaustivity.yml b/bench/profiles/exhaustivity.yml index d8295a27060e..0591bb0c4d56 100644 --- a/bench/profiles/exhaustivity.yml +++ b/bench/profiles/exhaustivity.yml @@ -50,28 +50,28 @@ charts: scripts: patmatexhaust: - - measure 20 40 3 $PROG_HOME/dotty/tests/bench/patmatexhaust.scala + - measure -wi 20 -i 40 -f 3 -- $PROG_HOME/dotty/tests/bench/patmatexhaust.scala exhaustivity-I: - - measure 20 40 3 $PROG_HOME/dotty/tests/bench/exhaustivity-I.scala + - measure -wi 20 -i 40 -f 3 -- $PROG_HOME/dotty/tests/bench/exhaustivity-I.scala exhaustivity-S: - - measure 20 40 3 $PROG_HOME/dotty/tests/bench/exhaustivity-S.scala + - measure -wi 20 -i 40 -f 3 -- $PROG_HOME/dotty/tests/bench/exhaustivity-S.scala exhaustivity-T: - - measure 20 40 3 $PROG_HOME/dotty/tests/bench/exhaustivity-T.scala + - measure -wi 20 -i 40 -f 3 -- $PROG_HOME/dotty/tests/bench/exhaustivity-T.scala exhaustivity-V: - - measure 20 40 3 $PROG_HOME/dotty/tests/bench/exhaustivity-V.scala + - measure -wi 20 -i 40 -f 3 -- $PROG_HOME/dotty/tests/bench/exhaustivity-V.scala exhaustivity-mips: - - measure 20 40 3 $PROG_HOME/dotty/tests/patmat/i7186.scala + - measure -wi 20 -i 40 -f 3 -- $PROG_HOME/dotty/tests/patmat/i7186.scala exhaustivity-i12241: - - measure 20 40 3 $PROG_HOME/dotty/tests/patmat/i12241.scala + - measure -wi 20 -i 40 -f 3 -- $PROG_HOME/dotty/tests/patmat/i12241.scala exhaustivity-i12358: - - measure 20 40 3 $PROG_HOME/dotty/tests/patmat/i12358.scala + - measure -wi 20 -i 40 -f 3 -- $PROG_HOME/dotty/tests/patmat/i12358.scala config: pr_base_url: "https://github.com/lampepfl/dotty/pull/" diff --git a/bench/profiles/implicits.yml b/bench/profiles/implicits.yml index d20a99c26461..97b0840d17c2 100644 --- a/bench/profiles/implicits.yml +++ b/bench/profiles/implicits.yml @@ -30,19 +30,19 @@ charts: scripts: implicit-cache: - - measure $PROG_HOME/dotty/tests/bench/implicit_cache.scala + - measure -- $PROG_HOME/dotty/tests/bench/implicit_cache.scala implicit-cache-from-tasty: - source $PROG_HOME/dotty/bench/scripts/implicit-cache-from-tasty implicit-scope-loop: - - measure $PROG_HOME/dotty/tests/bench/implicit-scope-loop.scala + - measure -- $PROG_HOME/dotty/tests/bench/implicit-scope-loop.scala inductive-implicits: - - measure $PROG_HOME/dotty/tests/bench/inductive-implicits.scala + - measure -- $PROG_HOME/dotty/tests/bench/inductive-implicits.scala implicitNums: - - measure $PROG_HOME/dotty/tests/bench/implicitNums.scala + - measure -- $PROG_HOME/dotty/tests/bench/implicitNums.scala implicitNums-from-tasty: - source $PROG_HOME/dotty/bench/scripts/implicitNums-from-tasty diff --git a/bench/profiles/misc.yml b/bench/profiles/misc.yml index 80172fc791ed..f0b6a5d11ed8 100644 --- a/bench/profiles/misc.yml +++ b/bench/profiles/misc.yml @@ -15,7 +15,7 @@ charts: scripts: i1535: - - measure $PROG_HOME/dotty/tests/bench/i1535.scala + - measure -- $PROG_HOME/dotty/tests/bench/i1535.scala i1687: - - measure $PROG_HOME/dotty/tests/bench/i1687.scala + - measure -- $PROG_HOME/dotty/tests/bench/i1687.scala diff --git a/bench/profiles/projects.yml b/bench/profiles/projects.yml index 2d96fb732910..10e90eb1c5d3 100644 --- a/bench/profiles/projects.yml +++ b/bench/profiles/projects.yml @@ -26,10 +26,10 @@ charts: scripts: dotty: - - measure -with-compiler $(find $PROG_HOME/dotty/compiler/src/dotty -name *.scala -o -name *.java) + - measure -- -with-compiler $ $(find $PROG_HOME/dotty/compiler/src/dotty -name *.scala -o -name *.java) re2s: - - measure $(find $PROG_HOME/tests/re2s/src -name *.scala) + - measure -- $(find $PROG_HOME/tests/re2s/src -name *.scala) # scalapb: # - source $PROG_HOME/dotty/bench/scripts/scalapb diff --git a/bench/profiles/sbt.yml b/bench/profiles/sbt.yml index 3ab0e43f3db2..0503a35d36a7 100644 --- a/bench/profiles/sbt.yml +++ b/bench/profiles/sbt.yml @@ -9,7 +9,7 @@ charts: scripts: dotty-sbt: - - measure -with-compiler -Yforce-sbt-phases -with-dotty $(find $PROG_HOME/dotty/compiler/src/dotty -name *.scala -o -name *.java) + - measure -- -with-compiler $ -Yforce-sbt-phases -with-dotty $(find $PROG_HOME/dotty/compiler/src/dotty -name *.scala -o -name *.java) config: pr_base_url: "https://github.com/lampepfl/dotty/pull/" diff --git a/bench/profiles/tuples.yml b/bench/profiles/tuples.yml index eaa2f302a885..7977644a5731 100644 --- a/bench/profiles/tuples.yml +++ b/bench/profiles/tuples.yml @@ -44,19 +44,19 @@ charts: scripts: tuple22-creation-apply: - - measure $PROG_HOME/dotty/tests/bench/tuple22-creation-apply.scala + - measure -- $PROG_HOME/dotty/tests/bench/tuple22-creation-apply.scala tuple22-creation-cons: - - measure $PROG_HOME/dotty/tests/bench/tuple22-creation-cons.scala + - measure -- $PROG_HOME/dotty/tests/bench/tuple22-creation-cons.scala tuple22-tails: - - measure $PROG_HOME/dotty/tests/bench/tuple22-tails.scala + - measure -- $PROG_HOME/dotty/tests/bench/tuple22-tails.scala tuple22-apply: - - measure $PROG_HOME/dotty/tests/bench/tuple22-apply.scala + - measure -- $PROG_HOME/dotty/tests/bench/tuple22-apply.scala tuple22-size: - - measure $PROG_HOME/dotty/tests/bench/tuple22-size.scala + - measure -- $PROG_HOME/dotty/tests/bench/tuple22-size.scala tuple-reverse: - measure-run TupleOps.reverse diff --git a/bench/profiles/typing.yml b/bench/profiles/typing.yml index 4df33da49d32..24a8835aeb55 100644 --- a/bench/profiles/typing.yml +++ b/bench/profiles/typing.yml @@ -8,7 +8,7 @@ charts: scripts: find-ref: - - measure $PROG_HOME/dotty/tests/bench/FindRef.scala + - measure -- $PROG_HOME/dotty/tests/bench/FindRef.scala config: pr_base_url: "https://github.com/lampepfl/dotty/pull/" diff --git a/bench/scripts/collection-vector.sh b/bench/scripts/collection-vector.sh index fb23a4a709db..65f6bdeb15a6 100755 --- a/bench/scripts/collection-vector.sh +++ b/bench/scripts/collection-vector.sh @@ -1,2 +1,2 @@ #!/usr/bin/env bash -sbt "dotty-bench-bootstrapped/jmh:run 40 40 3 bench/tests/Vector.scala" +sbt "dotty-bench-bootstrapped/jmh:run -wi 40 -i 40 -f 3 -- bench/tests/Vector.scala" diff --git a/bench/scripts/compiler-cold.sh b/bench/scripts/compiler-cold.sh index 06c1e3823a50..a7b5e0a5e2d1 100755 --- a/bench/scripts/compiler-cold.sh +++ b/bench/scripts/compiler-cold.sh @@ -1,2 +1,2 @@ #!/usr/bin/env bash -find compiler/src/ -type f \( -name "*.scala" -or -name "*.java" \) -exec echo "dotty-bench-bootstrapped/jmh:run 0 1 10" {} + | sbt +find compiler/src/ -type f \( -name "*.scala" -or -name "*.java" \) -exec echo "dotty-bench-bootstrapped/jmh:run -wi 0 -i 1 -f 10 -- " {} + | sbt diff --git a/bench/scripts/compiler.sh b/bench/scripts/compiler.sh index 0d1491d88676..ff8c9f5ca907 100755 --- a/bench/scripts/compiler.sh +++ b/bench/scripts/compiler.sh @@ -1,2 +1,2 @@ #!/usr/bin/env bash -find compiler/src/ -type f \( -name "*.scala" -or -name "*.java" \) -exec echo "dotty-bench-bootstrapped/jmh:run 5 10" {} + | sbt +find compiler/src/ -type f \( -name "*.scala" -or -name "*.java" \) -exec echo "dotty-bench-bootstrapped/jmh:run -wi 5 -i 10 -- " {} + | sbt diff --git a/bench/scripts/library-cold.sh b/bench/scripts/library-cold.sh index 349be0cc282f..80b80aa0445c 100755 --- a/bench/scripts/library-cold.sh +++ b/bench/scripts/library-cold.sh @@ -1,2 +1,2 @@ #!/usr/bin/env bash -find library/src/ -type f \( -name "*.scala" -or -name "*.java" \) -exec echo "dotty-bench-bootstrapped/jmh:run 0 1 10" {} + | sbt +find library/src/ -type f \( -name "*.scala" -or -name "*.java" \) -exec echo "dotty-bench-bootstrapped/jmh:run -wi 0 -i 1 -f 10 -- " {} + | sbt diff --git a/bench/scripts/library.sh b/bench/scripts/library.sh index b811349f85ec..40245b06bf28 100755 --- a/bench/scripts/library.sh +++ b/bench/scripts/library.sh @@ -1,2 +1,2 @@ #!/usr/bin/env bash -find library/src/ -type f \( -name "*.scala" -or -name "*.java" \) -exec echo "dotty-bench-bootstrapped/jmh:run 40 30" {} + | sbt +find library/src/ -type f \( -name "*.scala" -or -name "*.java" \) -exec echo "dotty-bench-bootstrapped/jmh:run -wi 40 -i 30 -- " {} + | sbt diff --git a/bench/src/main/scala/Benchmarks.scala b/bench/src/main/scala/Benchmarks.scala index 6e0bae6e72de..81346c596927 100644 --- a/bench/src/main/scala/Benchmarks.scala +++ b/bench/src/main/scala/Benchmarks.scala @@ -7,7 +7,7 @@ import reporting._ import org.openjdk.jmh.results.RunResult import org.openjdk.jmh.runner.Runner -import org.openjdk.jmh.runner.options.OptionsBuilder +import org.openjdk.jmh.runner.options.{OptionsBuilder, CommandLineOptions} import org.openjdk.jmh.annotations._ import org.openjdk.jmh.results.format._ import java.util.concurrent.TimeUnit @@ -22,37 +22,47 @@ import dotty.tools.io.AbstractFile object Bench { val COMPILE_OPTS_FILE = "compile.txt" + def printUsage() = + println("Usage (from SBT): scala3-bench/jmh:run -- ") + println("Display JMH help: scala3-bench/jmh:run -h") + println("Our default JMH options: -wi 30 -i 20 -f 3 -tu ms -bm AverageTime -jvmArgs \"-Xms2G -Xmx2G\"") + def main(args: Array[String]): Unit = { if (args.isEmpty) { - println("Missing ") + println("Missing arguments.") + printUsage() return } - val (intArgs, args1) = args.span(x => try { x.toInt; true } catch { case _: Throwable => false } ) - val warmup = if (intArgs.length > 0) intArgs(0).toInt else 30 - val iterations = if (intArgs.length > 1) intArgs(1).toInt else 20 - val forks = if (intArgs.length > 2) intArgs(2).toInt else 1 + val (jmhArgs, _scalacArgs) = args.span(_ != "--") + val scalacArgs = _scalacArgs.drop(1) + storeCompileOptions(scalacArgs) - import File.{ separator => sep } + val jmhCliOps = new CommandLineOptions(jmhArgs:_*) + val jmhOps = new OptionsBuilder().parent(jmhCliOps) + + // set our own default options + if !jmhCliOps.shouldFailOnError().hasValue() then jmhOps.shouldFailOnError(true) + if !jmhCliOps.getWarmupIterations().hasValue() then jmhOps.warmupIterations(30) + if !jmhCliOps.getMeasurementIterations().hasValue() then jmhOps.measurementIterations(20) + if !jmhCliOps.getForkCount().hasValue() then jmhOps.forks(1) + if jmhCliOps.getBenchModes().isEmpty() then jmhOps.mode(Mode.AverageTime) + if !jmhCliOps.getTimeUnit().hasValue() then jmhOps.timeUnit(TimeUnit.MILLISECONDS) + if !jmhCliOps.getJvmArgs().hasValue() then jmhOps.jvmArgs("-Xms2G", "-Xmx2G") + + val runner = new Runner(jmhOps.build()) + + if jmhCliOps.shouldHelp() then + printUsage() + println("Following is the JMH options documentation.") + println("-------------------------------------------") + return jmhCliOps.showHelp() + if jmhCliOps.shouldList() then return runner.list() + if jmhCliOps.shouldListWithParams() then return runner.listWithParams(jmhCliOps) + if jmhCliOps.shouldListProfilers() then return jmhCliOps.listProfilers() + if jmhCliOps.shouldListResultFormats() then return jmhCliOps.listResultFormats() - val args2 = args1.map { arg => - if ((arg.endsWith(".scala") || arg.endsWith(".java")) && !(new File(arg)).isAbsolute) ".." + sep + arg - else arg - } - storeCompileOptions(args2) - - val opts = new OptionsBuilder() - .shouldFailOnError(true) - .jvmArgs("-Xms2G", "-Xmx2G") - .mode(Mode.AverageTime) - .timeUnit(TimeUnit.MILLISECONDS) - .warmupIterations(warmup) - .measurementIterations(iterations) - .forks(forks) - .build - - val runner = new Runner(opts) // full access to all JMH features, you can also provide a custom output Format here runner.run() // actually run the benchmarks removeCompileOptions @@ -61,13 +71,17 @@ object Bench { def removeCompileOptions: Unit = new File(COMPILE_OPTS_FILE).delete() def storeCompileOptions(args: Array[String]): Unit = { + import File.{ separator => sep } + val standard_libs = System.getProperty("BENCH_CLASS_PATH") val compiler_libs = System.getProperty("BENCH_COMPILER_CLASS_PATH") val libs = if (args.contains("-with-compiler")) compiler_libs else standard_libs - var argsNorm = args.filter(_ != "-with-compiler") + var argsNorm = args.filter(_ != "-with-compiler").map { arg => + if ((arg.endsWith(".scala") || arg.endsWith(".java")) && !(new File(arg)).isAbsolute) ".." + sep + arg + else arg + } - import File.{ pathSeparator => sep } var cpIndex = argsNorm.indexOf("-classpath") if (cpIndex == -1) cpIndex = argsNorm.indexOf("-cp") if (cpIndex != -1) argsNorm(cpIndex + 1) = argsNorm(cpIndex + 1) + sep + libs From 7170f0d3fd1b20c41903758d64bce8d8ec7ef8a1 Mon Sep 17 00:00:00 2001 From: Matthieu Bovel Date: Thu, 21 Oct 2021 16:30:53 +0200 Subject: [PATCH 0752/1244] Update scala3-bench calls in bootstrapCmdTests --- project/scripts/bootstrapCmdTests | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/project/scripts/bootstrapCmdTests b/project/scripts/bootstrapCmdTests index 0dfa3460eeaa..9f8956e1d23c 100755 --- a/project/scripts/bootstrapCmdTests +++ b/project/scripts/bootstrapCmdTests @@ -5,10 +5,10 @@ set -e source $(dirname $0)/cmdTestsCommon.inc.sh # check that benchmarks can run -"$SBT" "scala3-bench/jmh:run 1 1 tests/pos/alias.scala" +"$SBT" "scala3-bench/jmh:run -wi 1 -i 1 -- tests/pos/alias.scala" # The above is here as it relies on the bootstrapped library. -"$SBT" "scala3-bench-bootstrapped/jmh:run 1 1 tests/pos/alias.scala" -"$SBT" "scala3-bench-bootstrapped/jmh:run 1 1 -with-compiler compiler/src/dotty/tools/dotc/core/Types.scala" +"$SBT" "scala3-bench-bootstrapped/jmh:run -wi 1 -i 1 -- tests/pos/alias.scala" +"$SBT" "scala3-bench-bootstrapped/jmh:run -wi 1 -i 1 -- -with-compiler compiler/src/dotty/tools/dotc/core/Types.scala" echo "testing scala.quoted.Expr.run from sbt scala" "$SBT" ";scala3-compiler-bootstrapped/scalac -with-compiler tests/run-staging/quote-run.scala; scala3-compiler-bootstrapped/scala -with-compiler Test" > "$tmp" From 70e4f4dca8534f7de0ecf58efc9929c7b485ef87 Mon Sep 17 00:00:00 2001 From: Stephane MICHELOUD Date: Thu, 21 Oct 2021 20:06:13 +0200 Subject: [PATCH 0753/1244] small additions to batch files (see PR#13577 and PR#13759) --- dist/bin/scalac.bat | 4 +++- dist/bin/scaladoc.bat | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/dist/bin/scalac.bat b/dist/bin/scalac.bat index bf34f9275aab..a94bdb5f88b8 100644 --- a/dist/bin/scalac.bat +++ b/dist/bin/scalac.bat @@ -39,8 +39,10 @@ if "%_PROG_NAME%"=="%_SCRIPTING_MAIN%" ( if defined JAVA_OPTS ( set _JAVA_OPTS=%JAVA_OPTS% ) else ( set _JAVA_OPTS=%_DEFAULT_JAVA_OPTS% ) +for %%i in ("%_PROG_HOME%\..") do set "_SCALA_HOME=%%~fi" + call "%_JAVACMD%" %_JAVA_OPTS% %_JAVA_DEBUG% %_JAVA_ARGS% %_JVM_CP_ARGS% ^ --Dscala.usejavacp=true ^ +-Dscala.home="%_SCALA_HOME%" -Dscala.usejavacp=true ^ %_PROG_NAME% %_SCALA_ARGS% %_RESIDUAL_ARGS% %_SCRIPTING_STRING% if not %ERRORLEVEL%==0 ( set _EXITCODE=1 diff --git a/dist/bin/scaladoc.bat b/dist/bin/scaladoc.bat index c7eb4cb6d472..2a80916c1db7 100644 --- a/dist/bin/scaladoc.bat +++ b/dist/bin/scaladoc.bat @@ -149,7 +149,7 @@ goto :eof @rem output parameter: _CLASS_PATH :updateClasspath set "__PATTERN=%~1" -for /f %%f in ('dir /a-d /b "%_LIB_DIR%\*%__PATTERN%*"') do ( +for /f "delims=" %%f in ('dir /a-d /b "%_LIB_DIR%\*%__PATTERN%*"') do ( set "_CLASS_PATH=!_CLASS_PATH!%_LIB_DIR%\%%f%_PSEP%" ) goto :eof From 923213404db11acd5982cbd955bf140320985f3f Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 21 Oct 2021 10:33:06 +0200 Subject: [PATCH 0754/1244] Improve message when -Xmax-inlines limit reached Fixes #13044 --- .../dotty/tools/dotc/transform/Erasure.scala | 10 +++- .../dotty/tools/dotc/CompilationTests.scala | 1 + tests/neg/i13044.check | 44 ++++++++++++++++ tests/neg/i13044.scala | 51 +++++++++++++++++++ tests/pos-custom-args/i13044.scala | 51 +++++++++++++++++++ 5 files changed, 155 insertions(+), 2 deletions(-) create mode 100644 tests/neg/i13044.check create mode 100644 tests/neg/i13044.scala create mode 100644 tests/pos-custom-args/i13044.scala diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index 2875e2e2d865..ae2eac2c20fd 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -593,8 +593,14 @@ object Erasure { */ private def checkNotErased(tree: Tree)(using Context): tree.type = { if (!ctx.mode.is(Mode.Type)) { - if (isErased(tree)) - report.error(em"${tree.symbol} is declared as erased, but is in fact used", tree.srcPos) + if isErased(tree) then + val msg = + if tree.symbol.is(Flags.Inline) then + em"""${tree.symbol} is declared as `inline`, but was not inlined + | + |Try increasing `-Xmax-inlines` above ${ctx.settings.XmaxInlines.value}""".stripMargin + else em"${tree.symbol} is declared as `erased`, but is in fact used" + report.error(msg, tree.srcPos) tree.symbol.getAnnotation(defn.CompileTimeOnlyAnnot) match { case Some(annot) => def defaultMsg = diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index c94ebe563f72..a9e679eb6e95 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -63,6 +63,7 @@ class CompilationTests { compileFile("tests/pos-special/extend-java-enum.scala", defaultOptions.and("-source", "3.0-migration")), compileFile("tests/pos-custom-args/help.scala", defaultOptions.and("-help", "-V", "-W", "-X", "-Y")), compileFile("tests/pos-custom-args/i10383.scala", defaultOptions.and("-source", "future", "-deprecation", "-Xfatal-warnings")), + compileFile("tests/pos-custom-args/i13044.scala", defaultOptions.and("-Xmax-inlines:33")), ).checkCompile() } diff --git a/tests/neg/i13044.check b/tests/neg/i13044.check new file mode 100644 index 000000000000..87b8a1fe9ae2 --- /dev/null +++ b/tests/neg/i13044.check @@ -0,0 +1,44 @@ +-- Error: tests/neg/i13044.scala:50:40 --------------------------------------------------------------------------------- +50 | implicit def typeSchema: Schema[A] = Schema.gen // error // error + | ^^^^^^^^^^ + | given instance gen is declared as `inline`, but was not inlined + | + | Try increasing `-Xmax-inlines` above 32 + | This location contains code that was inlined from i13044.scala:17 + | This location contains code that was inlined from i13044.scala:31 + | This location contains code that was inlined from i13044.scala:37 + | This location contains code that was inlined from i13044.scala:17 + | This location contains code that was inlined from i13044.scala:31 + | This location contains code that was inlined from i13044.scala:37 + | This location contains code that was inlined from i13044.scala:17 + | This location contains code that was inlined from i13044.scala:31 + | This location contains code that was inlined from i13044.scala:37 + | This location contains code that was inlined from i13044.scala:17 + | This location contains code that was inlined from i13044.scala:31 + | This location contains code that was inlined from i13044.scala:37 + | This location contains code that was inlined from i13044.scala:17 + | This location contains code that was inlined from i13044.scala:18 + | This location contains code that was inlined from i13044.scala:31 + | This location contains code that was inlined from i13044.scala:37 +-- Error: tests/neg/i13044.scala:50:40 --------------------------------------------------------------------------------- +50 | implicit def typeSchema: Schema[A] = Schema.gen // error // error + | ^^^^^^^^^^ + | method recurse is declared as `inline`, but was not inlined + | + | Try increasing `-Xmax-inlines` above 32 + | This location contains code that was inlined from i13044.scala:18 + | This location contains code that was inlined from i13044.scala:31 + | This location contains code that was inlined from i13044.scala:37 + | This location contains code that was inlined from i13044.scala:17 + | This location contains code that was inlined from i13044.scala:31 + | This location contains code that was inlined from i13044.scala:37 + | This location contains code that was inlined from i13044.scala:17 + | This location contains code that was inlined from i13044.scala:31 + | This location contains code that was inlined from i13044.scala:37 + | This location contains code that was inlined from i13044.scala:17 + | This location contains code that was inlined from i13044.scala:31 + | This location contains code that was inlined from i13044.scala:37 + | This location contains code that was inlined from i13044.scala:17 + | This location contains code that was inlined from i13044.scala:18 + | This location contains code that was inlined from i13044.scala:31 + | This location contains code that was inlined from i13044.scala:37 diff --git a/tests/neg/i13044.scala b/tests/neg/i13044.scala new file mode 100644 index 000000000000..081b642c604c --- /dev/null +++ b/tests/neg/i13044.scala @@ -0,0 +1,51 @@ +import scala.deriving.Mirror +import scala.compiletime._ + +trait Schema[T] { + def build: T +} + +object Schema extends SchemaDerivation { + implicit lazy val int: Schema[Int] = ??? + implicit def option[A](implicit ev: Schema[A]): Schema[Option[A]] = ??? +} + +trait SchemaDerivation { + inline def recurse[A <: Tuple]: List[Schema[Any]] = + inline erasedValue[A] match { + case _: (t *: ts) => + val builder = summonInline[Schema[t]].asInstanceOf[Schema[Any]] + builder :: recurse[ts] + case _: EmptyTuple => Nil + } + + inline def derived[A]: Schema[A] = + inline summonInline[Mirror.Of[A]] match { + case m: Mirror.SumOf[A] => + lazy val subTypes = recurse[m.MirroredElemTypes] + new Schema[A] { + def build: A = ??? + } + + case m: Mirror.ProductOf[A] => + lazy val fields = recurse[m.MirroredElemTypes] + new Schema[A] { + def build: A = ??? + } + } + + inline given gen[A]: Schema[A] = derived +} + +case class H(i: Int) +case class G(h: H) +case class F(g: G) +case class E(f: Option[F]) +case class D(e: E) +case class C(d: D) +case class B(c: C) +case class A(a: A, b: B) + +object TestApp { + implicit def typeSchema: Schema[A] = Schema.gen // error // error +} diff --git a/tests/pos-custom-args/i13044.scala b/tests/pos-custom-args/i13044.scala new file mode 100644 index 000000000000..33a20b5800c8 --- /dev/null +++ b/tests/pos-custom-args/i13044.scala @@ -0,0 +1,51 @@ +import scala.deriving.Mirror +import scala.compiletime._ + +trait Schema[T] { + def build: T +} + +object Schema extends SchemaDerivation { + implicit lazy val int: Schema[Int] = ??? + implicit def option[A](implicit ev: Schema[A]): Schema[Option[A]] = ??? +} + +trait SchemaDerivation { + inline def recurse[A <: Tuple]: List[Schema[Any]] = + inline erasedValue[A] match { + case _: (t *: ts) => + val builder = summonInline[Schema[t]].asInstanceOf[Schema[Any]] + builder :: recurse[ts] + case _: EmptyTuple => Nil + } + + inline def derived[A]: Schema[A] = + inline summonInline[Mirror.Of[A]] match { + case m: Mirror.SumOf[A] => + lazy val subTypes = recurse[m.MirroredElemTypes] + new Schema[A] { + def build: A = ??? + } + + case m: Mirror.ProductOf[A] => + lazy val fields = recurse[m.MirroredElemTypes] + new Schema[A] { + def build: A = ??? + } + } + + inline given gen[A]: Schema[A] = derived +} + +case class H(i: Int) +case class G(h: H) +case class F(g: G) +case class E(f: Option[F]) +case class D(e: E) +case class C(d: D) +case class B(c: C) +case class A(a: A, b: B) + +object TestApp { + implicit def typeSchema: Schema[A] = Schema.gen +} From dc94c7c752969878ff0cf862c1376350dd461295 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Tue, 27 Jul 2021 14:35:28 +0200 Subject: [PATCH 0755/1244] Add reflect TypeRepr.substituteTypes --- .../quoted/runtime/impl/QuotesImpl.scala | 2 ++ .../dotty/tools/repl/TabcompleteTests.scala | 2 +- library/src/scala/quoted/Quotes.scala | 6 +++++ project/MiMaFilters.scala | 5 ++-- tests/run-macros/i12392.check | 1 + tests/run-macros/i12392/Macros_1.scala | 24 +++++++++++++++++++ tests/run-macros/i12392/Test_2.scala | 1 + 7 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 tests/run-macros/i12392.check create mode 100644 tests/run-macros/i12392/Macros_1.scala create mode 100644 tests/run-macros/i12392/Test_2.scala diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index ab651408a0c4..8a8e34901a3b 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -1747,6 +1747,8 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler dotc.core.Types.decorateTypeApplications(self).appliedTo(targ) def appliedTo(targs: List[TypeRepr]): TypeRepr = dotc.core.Types.decorateTypeApplications(self).appliedTo(targs) + def substituteTypes(from: List[Symbol], to: List[TypeRepr]): TypeRepr = + self.subst(from, to) end extension end TypeReprMethods diff --git a/compiler/test/dotty/tools/repl/TabcompleteTests.scala b/compiler/test/dotty/tools/repl/TabcompleteTests.scala index 540147bcd211..932ab7058899 100644 --- a/compiler/test/dotty/tools/repl/TabcompleteTests.scala +++ b/compiler/test/dotty/tools/repl/TabcompleteTests.scala @@ -134,7 +134,7 @@ class TabcompleteTests extends ReplTest { } @Test def i12600 = fromInitialState { implicit s => - assertEquals(List("select", "show", "simplified"), + assertEquals(List("select", "show", "simplified", "substituteTypes"), tabComplete("import quoted.* ; def fooImpl(using Quotes): Expr[Int] = { import quotes.reflect.* ; TypeRepr.of[Int].s")) } diff --git a/library/src/scala/quoted/Quotes.scala b/library/src/scala/quoted/Quotes.scala index a1199fc42169..397f9d3b6aae 100644 --- a/library/src/scala/quoted/Quotes.scala +++ b/library/src/scala/quoted/Quotes.scala @@ -2565,6 +2565,12 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => /** The current type applied to given type arguments: `this[targ0, ..., targN]` */ def appliedTo(targs: List[TypeRepr]): TypeRepr + /** Substitute all types that refer in their symbol attribute to + * one of the symbols in `from` by the corresponding types in `to`. + */ + @experimental + def substituteTypes(from: List[Symbol], to: List[TypeRepr]): TypeRepr + end extension } diff --git a/project/MiMaFilters.scala b/project/MiMaFilters.scala index e37bce1b3cf9..4ef5e4d69c57 100644 --- a/project/MiMaFilters.scala +++ b/project/MiMaFilters.scala @@ -1,12 +1,13 @@ import com.typesafe.tools.mima.core._ -import com.typesafe.tools.mima.core.ProblemFilters._ object MiMaFilters { val Library: Seq[ProblemFilter] = Seq( // Experimental APIs that can be added in 3.2.0 ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.init"), ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.last"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.append") + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.append"), + ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#TypeReprMethods.substituteTypes"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.quoted.Quotes#reflectModule#TypeReprMethods.substituteTypes"), ) } diff --git a/tests/run-macros/i12392.check b/tests/run-macros/i12392.check new file mode 100644 index 000000000000..54c7f5d06c3f --- /dev/null +++ b/tests/run-macros/i12392.check @@ -0,0 +1 @@ +scala.Option[scala.Predef.String] to scala.Option[scala.Int] diff --git a/tests/run-macros/i12392/Macros_1.scala b/tests/run-macros/i12392/Macros_1.scala new file mode 100644 index 000000000000..f604cf815716 --- /dev/null +++ b/tests/run-macros/i12392/Macros_1.scala @@ -0,0 +1,24 @@ +import scala.quoted.* + +inline def testSubst: Unit = ${ testSubstImpl } + +def testSubstImpl(using Quotes): Expr[Unit] = { + import quotes.reflect.* + + val intTpe = TypeRepr.of[Int] + val strOptTpe = TypeRepr.of[Option[String]] + + val tpeArgs: List[TypeRepr] = strOptTpe match { + case AppliedType(_, args) => args + case _ => List.empty[TypeRepr] + } + + val intOptTpe = strOptTpe.substituteTypes( + tpeArgs.map(_.typeSymbol), List(intTpe)) + + val repr = s"${strOptTpe.show} to ${intOptTpe.show}" + + '{ + println(${Expr(repr)}) + } +} diff --git a/tests/run-macros/i12392/Test_2.scala b/tests/run-macros/i12392/Test_2.scala new file mode 100644 index 000000000000..6fb9577c8ef9 --- /dev/null +++ b/tests/run-macros/i12392/Test_2.scala @@ -0,0 +1 @@ +@main def Test = testSubst From b040199e20432c18bf8fe03de287fbe85094b295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Zyba=C5=82a?= Date: Fri, 22 Oct 2021 16:17:23 +0200 Subject: [PATCH 0756/1244] Fix missing known subtypes --- .../src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala | 5 ++++- .../transformers/InheritanceInformationTransformer.scala | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala index 09d71021a6f5..de3cb429922b 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala @@ -292,7 +292,10 @@ trait ClassLikeSupport: def getParentsAsTreeSymbolTuples: List[(Tree, Symbol)] = for parentTree <- c.parents if isValidPos(parentTree.pos) // We assume here that order is correct - parentSymbol = if parentTree.symbol.isClassConstructor then parentTree.symbol.owner else parentTree.symbol + parentSymbol = parentTree match + case t: TypeTree => t.tpe.typeSymbol + case tree if tree.symbol.isClassConstructor => tree.symbol.owner + case tree => tree.symbol if parentSymbol != defn.ObjectClass && parentSymbol != defn.AnyClass yield (parentTree, parentSymbol) diff --git a/scaladoc/src/dotty/tools/scaladoc/transformers/InheritanceInformationTransformer.scala b/scaladoc/src/dotty/tools/scaladoc/transformers/InheritanceInformationTransformer.scala index 63774d27c1be..02e224f10cf0 100644 --- a/scaladoc/src/dotty/tools/scaladoc/transformers/InheritanceInformationTransformer.scala +++ b/scaladoc/src/dotty/tools/scaladoc/transformers/InheritanceInformationTransformer.scala @@ -3,7 +3,7 @@ package transformers class InheritanceInformationTransformer(using DocContext) extends (Module => Module): override def apply(original: Module): Module = - val subtypes = getSupertypes(original.rootPackage).groupBy(_._1).transform((k, v) => v.map(_._2)) + val subtypes = getSupertypes(original.rootPackage).groupMap(_(0))(_(1)) original.updateMembers { m => val edges = getEdges(m.asLink.copy(kind = bareClasslikeKind(m.kind)), subtypes) val st: Seq[LinkToType] = edges.map(_._1).distinct From fb3089bbd5a8ead61065c32e372be2869fd3f6ca Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Wed, 20 Oct 2021 18:43:20 +0200 Subject: [PATCH 0757/1244] Remove Type#hasNonWildcard{LowerBound, UpperBound} These are no longer needed since we stopped storing wildcards in constraints (see dropWildcards in ConstraintHandling#addOneBound). --- compiler/src/dotty/tools/dotc/core/Types.scala | 14 -------------- .../src/dotty/tools/dotc/typer/Inferencing.scala | 4 ++-- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 1d36efcb2a01..6650771963f9 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -4615,20 +4615,6 @@ object Types { /** For uninstantiated type variables: Is the upper bound different from Any? */ def hasUpperBound(using Context): Boolean = !currentEntry.hiBound.isRef(defn.AnyClass) - /** For uninstantiated type variables: Is the lower bound different from Nothing and - * does it not contain wildcard types? - */ - def hasNonWildcardLowerBound(using Context): Boolean = - val lo = currentEntry.loBound - !lo.isExactlyNothing && !lo.containsWildcardTypes - - /** For uninstantiated type variables: Is the upper bound different from Any and - * does it not contain wildcard types? - */ - def hasNonWildcardUpperBound(using Context): Boolean = - val hi = currentEntry.hiBound - !hi.isRef(defn.AnyClass) && !hi.containsWildcardTypes - /** Unwrap to instance (if instantiated) or origin (if not), until result * is no longer a TypeVar */ diff --git a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala index 7654b98995ff..d0565857db91 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala @@ -179,9 +179,9 @@ object Inferencing { && { val direction = instDirection(tvar.origin) if minimizeSelected then - if direction <= 0 && tvar.hasNonWildcardLowerBound then + if direction <= 0 && tvar.hasLowerBound then instantiate(tvar, fromBelow = true) - else if direction >= 0 && tvar.hasNonWildcardUpperBound then + else if direction >= 0 && tvar.hasUpperBound then instantiate(tvar, fromBelow = false) // else hold off instantiating unbounded unconstrained variable else if direction != 0 then From 18df21c77d839c6c1b91146cb6c46377c1e46976 Mon Sep 17 00:00:00 2001 From: danicheg Date: Sun, 24 Oct 2021 15:51:40 +0300 Subject: [PATCH 0758/1244] Fix links to the migration guide --- library/src/scala/runtime/stdLibPatches/language.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/src/scala/runtime/stdLibPatches/language.scala b/library/src/scala/runtime/stdLibPatches/language.scala index d7084e8850d8..4a70bede8e8a 100644 --- a/library/src/scala/runtime/stdLibPatches/language.scala +++ b/library/src/scala/runtime/stdLibPatches/language.scala @@ -136,14 +136,14 @@ object language: /** Set source version to 3.0-migration. * - * @see [[https://scalacenter.github.io/scala-3-migration-guide/docs/scala-3-migration-mode]] + * @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]] */ @compileTimeOnly("`3.0-migration` can only be used at compile time in import statements") object `3.0-migration` /** Set source version to 3.0. * - * @see [[https://scalacenter.github.io/scala-3-migration-guide/docs/scala-3-migration-mode]] + * @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]] */ @compileTimeOnly("`3.0` can only be used at compile time in import statements") object `3.0` @@ -151,13 +151,13 @@ object language: /* This can be added when we go to 3.1 /** Set source version to 3.1-migration. * - * @see [[https://scalacenter.github.io/scala-3-migration-guide/docs/scala-3-migration-mode]] + * @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]] */ object `3.1-migration` /** Set source version to 3.1 * - * @see [[https://scalacenter.github.io/scala-3-migration-guide/docs/scala-3-migration-mode]] + * @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]] */ object `3.1` */ From 7cef26c63bf1dbddcd0b75b6de617c47da6759b9 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 25 Oct 2021 12:11:24 +0200 Subject: [PATCH 0759/1244] Fix error message when deriving an obstract type Fixes #13808 --- compiler/src/dotty/tools/dotc/typer/Deriving.scala | 5 ++++- tests/neg/i13808.check | 8 ++++++++ tests/neg/i13808.scala | 14 ++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 tests/neg/i13808.check create mode 100644 tests/neg/i13808.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Deriving.scala b/compiler/src/dotty/tools/dotc/typer/Deriving.scala index a8de83664001..39a775d61f8c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Deriving.scala +++ b/compiler/src/dotty/tools/dotc/typer/Deriving.scala @@ -83,7 +83,10 @@ trait Deriving { */ private def processDerivedInstance(derived: untpd.Tree): Unit = { val originalTypeClassType = typedAheadType(derived, AnyTypeConstructorProto).tpe - val typeClassType = checkClassType(underlyingClassRef(originalTypeClassType), derived.srcPos, traitReq = false, stablePrefixReq = true) + val underlyingClassType = underlyingClassRef(originalTypeClassType) + val typeClassType = checkClassType( + underlyingClassType.orElse(originalTypeClassType), + derived.srcPos, traitReq = false, stablePrefixReq = true) val typeClass = typeClassType.classSymbol val typeClassParams = typeClass.typeParams val typeClassArity = typeClassParams.length diff --git a/tests/neg/i13808.check b/tests/neg/i13808.check new file mode 100644 index 000000000000..e9b55a5ddec2 --- /dev/null +++ b/tests/neg/i13808.check @@ -0,0 +1,8 @@ +-- Error: tests/neg/i13808.scala:13:37 --------------------------------------------------------------------------------- +13 |case class Boom[A](value: A) derives OpaqueType, Foo // error // error + | ^^^^^^^^^^ + | OpaqueTypes.OpaqueType is not a class type +-- Error: tests/neg/i13808.scala:13:49 --------------------------------------------------------------------------------- +13 |case class Boom[A](value: A) derives OpaqueType, Foo // error // error + | ^^^ + | FooModule.Foo is not a class type diff --git a/tests/neg/i13808.scala b/tests/neg/i13808.scala new file mode 100644 index 000000000000..6dd568c69423 --- /dev/null +++ b/tests/neg/i13808.scala @@ -0,0 +1,14 @@ +object OpaqueTypes: + opaque type OpaqueType[A] = List[A] + object OpaqueType: + def derived[A]: OpaqueType[A] = Nil + +object FooModule: + type Foo[A] + object Foo: + def derived[A]: Foo[A] = Nil.asInstanceOf[Foo[A]] + +import FooModule.Foo +import OpaqueTypes.OpaqueType +case class Boom[A](value: A) derives OpaqueType, Foo // error // error + From 5e7233fc3eee6efb8aa567e684d0507457f8cefa Mon Sep 17 00:00:00 2001 From: adampauls Date: Fri, 15 Oct 2021 16:49:30 -0700 Subject: [PATCH 0760/1244] Remove stateful enterSyms. More unused. --- .../src/dotty/tools/dotc/ast/Desugar.scala | 23 ------------------ .../dotty/tools/dotc/typer/TyperPhase.scala | 24 +++---------------- 2 files changed, 3 insertions(+), 44 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index a71fc3d40e92..b652a49c0381 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -1410,29 +1410,6 @@ object desugar { FunctionWithMods(params, body, Modifiers(mods)) } - /** Add annotation to tree: - * tree @fullName - * - * The annotation is usually represented as a TypeTree referring to the class - * with the given name `fullName`. However, if the annotation matches a file name - * that is still to be entered, the annotation is represented as a cascade of `Selects` - * following `fullName`. This is necessary so that we avoid reading an annotation from - * the classpath that is also compiled from source. - */ - def makeAnnotated(fullName: String, tree: Tree)(using Context): Annotated = { - val parts = fullName.split('.') - val ttree = typerPhase match { - case phase: TyperPhase if phase.stillToBeEntered(parts.last) => - val prefix = - parts.init.foldLeft(Ident(nme.ROOTPKG): Tree)((qual, name) => - Select(qual, name.toTermName)) - Select(prefix, parts.last.toTypeName) - case _ => - TypeTree(requiredClass(fullName).typeRef) - } - Annotated(tree, New(ttree, Nil)) - } - private def derivedValDef(original: Tree, named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers)(using Context) = { val vdef = ValDef(named.name.asTermName, tpt, rhs) .withMods(mods) diff --git a/compiler/src/dotty/tools/dotc/typer/TyperPhase.scala b/compiler/src/dotty/tools/dotc/typer/TyperPhase.scala index bb1bfbea28e5..a8a2ff95687a 100644 --- a/compiler/src/dotty/tools/dotc/typer/TyperPhase.scala +++ b/compiler/src/dotty/tools/dotc/typer/TyperPhase.scala @@ -31,15 +31,6 @@ class TyperPhase(addRootImports: Boolean = true) extends Phase { override def allowsImplicitSearch: Boolean = true - /** The contexts for compilation units that are parsed but not yet entered */ - private var remaining: List[Context] = Nil - - /** Does a source file ending with `.scala` belong to a compilation unit - * that is parsed but not yet entered? - */ - def stillToBeEntered(name: String): Boolean = - remaining.exists(_.compilationUnit.toString.endsWith(name + ".scala")) - // Run regardless of parsing errors override def isRunnable(implicit ctx: Context): Boolean = true @@ -68,13 +59,6 @@ class TyperPhase(addRootImports: Boolean = true) extends Phase { JavaChecks.check(unit.tpdTree) } - - private def firstTopLevelDef(trees: List[tpd.Tree])(using Context): Symbol = trees match - case PackageDef(_, defs) :: _ => firstTopLevelDef(defs) - case Import(_, _) :: defs => firstTopLevelDef(defs) - case (tree @ TypeDef(_, _)) :: _ => tree.symbol - case _ => NoSymbol - protected def discardAfterTyper(unit: CompilationUnit)(using Context): Boolean = unit.isJava || unit.suspended @@ -89,11 +73,9 @@ class TyperPhase(addRootImports: Boolean = true) extends Phase { else newCtx - remaining = unitContexts - while remaining.nonEmpty do - enterSyms(using remaining.head) - remaining = remaining.tail - val firstXmlPos = ctx.base.parserPhase match { + unitContexts.foreach(enterSyms(using _)) + + ctx.base.parserPhase match { case p: ParserPhase => if p.firstXmlPos.exists && !defn.ScalaXmlPackageClass.exists then report.error( From 5020797212e12d1f03fc13ff134c888b317b0070 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Mon, 25 Oct 2021 18:49:40 +0200 Subject: [PATCH 0761/1244] Add annotations to semanticdb Previously, it was not possible to find if a given method was for example annotated with @main, which will be useful for run/debug code lenses. Now, they should be correctly saved. The only issue seems to be `@specialized` which is currently producing empty type, anone knows what is going on? --- .../dotty/tools/dotc/semanticdb/PPrint.scala | 3 ++ .../dotty/tools/dotc/semanticdb/Scala3.scala | 5 +++ tests/semanticdb/metac.expect | 38 +++++++++---------- 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/semanticdb/PPrint.scala b/compiler/src/dotty/tools/dotc/semanticdb/PPrint.scala index 2f1e2b760f1c..4361db3e50d6 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/PPrint.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/PPrint.scala @@ -35,6 +35,9 @@ class SymbolInformationPrinter (symtab: PrinterSymtab): case Reference, Definition def pprint(info: SymbolInformation): String = val sb = new StringBuilder() + val annotStr = info.annotations.map(pprint).mkString(" ") + if annotStr.nonEmpty then + sb.append(annotStr + " ") sb.append(accessString(info.access)) if info.isAbstract then sb.append("abstract ") if info.isFinal then sb.append("final ") diff --git a/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala b/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala index c8d418f236c7..a99e7c191601 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala @@ -95,6 +95,10 @@ object Scala3: val kind = s.symbolKind(symkinds) val sname = sym.symbolName val signature = s.info.toSemanticSig(s) + val symbolAnnotations = s.annotations.collect{ + case annot if annot.symbol != defn.BodyAnnot && annot.symbol != defn.ChildAnnot => + Annotation(annot.symbol.typeRef.toSemanticType(annot.symbol)) + } SymbolInformation( symbol = sname, language = Language.SCALA, @@ -104,6 +108,7 @@ object Scala3: signature = signature, access = s.symbolAccess(kind), overriddenSymbols = s.overriddenSymbols, + annotations = symbolAnnotations ) case s: WildcardTypeSymbol => SymbolInformation( diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index 44ddcf3cde8e..2c384c7d5f35 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -228,26 +228,26 @@ Occurrences => 48 entries Symbols: annot/Alias. => final object Alias extends Object { self: Alias.type => +2 decls } annot/Alias.A# => type A = ClassAnnotation @param -annot/Annotations# => class Annotations [typeparam T ] extends Object { self: AnyRef & Annotations[T] => +6 decls } -annot/Annotations#S# => type S -annot/Annotations#[T] => typeparam T -annot/Annotations#``(). => primary ctor [typeparam T ](param x: T): Annotations[T] -annot/Annotations#``().(x) => param x: T -annot/Annotations#field. => val method field Int -annot/Annotations#method(). => method method => Int -annot/Annotations#x. => private[this] val method x T +annot/Annotations# => @ClassAnnotation class Annotations [@TypeParameterAnnotation typeparam T ] extends Object { self: AnyRef & Annotations[T] => +6 decls } +annot/Annotations#S# => @TypeAnnotation type S +annot/Annotations#[T] => @TypeParameterAnnotation typeparam T +annot/Annotations#``(). => primary ctor [@TypeParameterAnnotation typeparam T ](@ParameterAnnotation param x: T): Annotations[T] +annot/Annotations#``().(x) => @ParameterAnnotation param x: T +annot/Annotations#field. => @FieldAnnotation val method field Int +annot/Annotations#method(). => @MethodAnnotation method method => Int +annot/Annotations#x. => @ParameterAnnotation private[this] val method x T annot/B# => class B extends Object { self: B => +3 decls } -annot/B#``(). => primary ctor (param x: Int): B +annot/B#``(). => @ConstructorAnnotation primary ctor (param x: Int): B annot/B#``().(x) => param x: Int -annot/B#``(+1). => ctor (): B +annot/B#``(+1). => @ConstructorAnnotation ctor (): B annot/B#x. => private[this] val method x Int -annot/M. => final object M extends Object { self: M.type => +1 decls } -annot/M.m(). => macro m [typeparam TT ]: Int +annot/M. => @ObjectAnnotation final object M extends Object { self: M.type => +1 decls } +annot/M.m(). => @MacroAnnotation macro m [typeparam TT ]: Int annot/M.m().[TT] => typeparam TT -annot/T# => trait T extends Object { self: T => +1 decls } +annot/T# => @TraitAnnotation trait T extends Object { self: T => +1 decls } annot/T#``(). => primary ctor (): T local0 => selfparam self: AnyRef -local1 => val local local: Int +local1 => @LocalAnnotation val local local: Int Occurrences: [0:8..0:13): annot <- annot/ @@ -4082,9 +4082,9 @@ flags/p/package.C#w(). => abstract method w => Int flags/p/package.C#x. => private[this] val method x T flags/p/package.C#y. => private[this] val method y U flags/p/package.C#z. => private[this] val method z V -flags/p/package.S# => class S [typeparam T ] extends Object { self: S[T] => +2 decls } -flags/p/package.S#[T] => typeparam T -flags/p/package.S#``(). => primary ctor [typeparam T ](): S[T] +flags/p/package.S# => class S [@specialized typeparam T ] extends Object { self: S[T] => +2 decls } +flags/p/package.S#[T] => @specialized typeparam T +flags/p/package.S#``(). => primary ctor [@specialized typeparam T ](): S[T] flags/p/package.T1# => type T1 = Int flags/p/package.T2# => type T2 [typeparam T ] = S[T] flags/p/package.T2#[T] => typeparam T @@ -4635,7 +4635,7 @@ Symbols: _empty_/MyProgram# => final class MyProgram extends Object { self: MyProgram => +2 decls } _empty_/readInts# => final class readInts extends Object { self: readInts => +2 decls } _empty_/toplevel$package. => final package object _empty_ extends Object { self: _empty_.type => +9 decls } -_empty_/toplevel$package.MyProgram(). => method MyProgram (param times: Int): Unit +_empty_/toplevel$package.MyProgram(). => @main method MyProgram (param times: Int): Unit _empty_/toplevel$package.MyProgram().(times) => param times: Int _empty_/toplevel$package.a. => val inline method a "" _empty_/toplevel$package.combine(). => method combine (param x: Int)(param y: Int): Int @@ -4648,7 +4648,7 @@ _empty_/toplevel$package.combine(+1).(z) => param z: Int _empty_/toplevel$package.combine(+2). => method combine => Int _empty_/toplevel$package.foo(). => method foo => String _empty_/toplevel$package.fooRef(). => method fooRef => String -_empty_/toplevel$package.readInts(). => method readInts (param ints: Int*): Unit +_empty_/toplevel$package.readInts(). => @main method readInts (param ints: Int*): Unit _empty_/toplevel$package.readInts().(ints) => param ints: Int* Occurrences: From b7c1f05b80f589db61f69dfe7837e61c8894011c Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Wed, 27 Oct 2021 11:58:50 +0200 Subject: [PATCH 0762/1244] Make sure annotation's type is fully represented in semanticdb --- .../dotty/tools/dotc/semanticdb/Scala3.scala | 2 +- .../expect/Annotations.expect.scala | 3 ++ tests/semanticdb/expect/Annotations.scala | 3 ++ tests/semanticdb/metac.expect | 37 +++++++++++-------- 4 files changed, 28 insertions(+), 17 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala b/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala index a99e7c191601..686dc20e481b 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala @@ -97,7 +97,7 @@ object Scala3: val signature = s.info.toSemanticSig(s) val symbolAnnotations = s.annotations.collect{ case annot if annot.symbol != defn.BodyAnnot && annot.symbol != defn.ChildAnnot => - Annotation(annot.symbol.typeRef.toSemanticType(annot.symbol)) + Annotation(annot.tree.tpe.toSemanticType(annot.symbol)) } SymbolInformation( symbol = sname, diff --git a/tests/semanticdb/expect/Annotations.expect.scala b/tests/semanticdb/expect/Annotations.expect.scala index 14976ad8aa2f..2422839c8307 100644 --- a/tests/semanticdb/expect/Annotations.expect.scala +++ b/tests/semanticdb/expect/Annotations.expect.scala @@ -22,6 +22,9 @@ class Annotations/*<-annot::Annotations#*/[@TypeParameterAnnotation/*->com::java class B/*<-annot::B#*/ @ConstructorAnnotation/*->com::javacp::annot::ConstructorAnnotation#*/()(x/*<-annot::B#x.*/: Int/*->scala::Int#*/) { @ConstructorAnnotation/*->com::javacp::annot::ConstructorAnnotation#*/ def this/*<-annot::B#``(+1).*/() = this(42) + + @throws/*->scala::throws#*/[Exception/*->scala::package.Exception#*/] + def throwing/*<-annot::B#throwing().*/ = throw new Exception/*->scala::package.Exception#*/("") } @ObjectAnnotation/*->com::javacp::annot::ObjectAnnotation#*/ diff --git a/tests/semanticdb/expect/Annotations.scala b/tests/semanticdb/expect/Annotations.scala index 176ced6487e8..0556a2299b80 100644 --- a/tests/semanticdb/expect/Annotations.scala +++ b/tests/semanticdb/expect/Annotations.scala @@ -22,6 +22,9 @@ class Annotations[@TypeParameterAnnotation T](@ParameterAnnotation x: T) { self: class B @ConstructorAnnotation()(x: Int) { @ConstructorAnnotation def this() = this(42) + + @throws[Exception] + def throwing = throw new Exception("") } @ObjectAnnotation diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index 2c384c7d5f35..07b3174b3d93 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -222,8 +222,8 @@ Schema => SemanticDB v4 Uri => Annotations.scala Text => empty Language => Scala -Symbols => 22 entries -Occurrences => 48 entries +Symbols => 23 entries +Occurrences => 52 entries Symbols: annot/Alias. => final object Alias extends Object { self: Alias.type => +2 decls } @@ -236,10 +236,11 @@ annot/Annotations#``().(x) => @ParameterAnnotation param x: T annot/Annotations#field. => @FieldAnnotation val method field Int annot/Annotations#method(). => @MethodAnnotation method method => Int annot/Annotations#x. => @ParameterAnnotation private[this] val method x T -annot/B# => class B extends Object { self: B => +3 decls } +annot/B# => class B extends Object { self: B => +4 decls } annot/B#``(). => @ConstructorAnnotation primary ctor (param x: Int): B annot/B#``().(x) => param x: Int annot/B#``(+1). => @ConstructorAnnotation ctor (): B +annot/B#throwing(). => @throws[Exception] method throwing => Nothing annot/B#x. => private[this] val method x Int annot/M. => @ObjectAnnotation final object M extends Object { self: M.type => +1 decls } annot/M.m(). => @MacroAnnotation macro m [typeparam TT ]: Int @@ -285,19 +286,23 @@ Occurrences: [21:36..21:39): Int -> scala/Int# [22:3..22:24): ConstructorAnnotation -> com/javacp/annot/ConstructorAnnotation# [23:6..23:10): <- annot/B#``(+1). -[26:1..26:17): ObjectAnnotation -> com/javacp/annot/ObjectAnnotation# -[27:7..27:8): M <- annot/M. -[28:3..28:18): MacroAnnotation -> com/javacp/annot/MacroAnnotation# -[29:6..29:7): m <- annot/M.m(). -[29:8..29:10): TT <- annot/M.m().[TT] -[29:13..29:16): Int -> scala/Int# -[29:25..29:28): ??? -> scala/Predef.`???`(). -[32:1..32:16): TraitAnnotation -> com/javacp/annot/TraitAnnotation# -[33:6..33:7): T <- annot/T# -[35:7..35:12): Alias <- annot/Alias. -[36:7..36:8): A <- annot/Alias.A# -[36:11..36:26): ClassAnnotation -> com/javacp/annot/ClassAnnotation# -[36:28..36:33): param -> scala/annotation/meta/param# +[25:3..25:9): throws -> scala/throws# +[25:10..25:19): Exception -> scala/package.Exception# +[26:6..26:14): throwing <- annot/B#throwing(). +[26:27..26:36): Exception -> scala/package.Exception# +[29:1..29:17): ObjectAnnotation -> com/javacp/annot/ObjectAnnotation# +[30:7..30:8): M <- annot/M. +[31:3..31:18): MacroAnnotation -> com/javacp/annot/MacroAnnotation# +[32:6..32:7): m <- annot/M.m(). +[32:8..32:10): TT <- annot/M.m().[TT] +[32:13..32:16): Int -> scala/Int# +[32:25..32:28): ??? -> scala/Predef.`???`(). +[35:1..35:16): TraitAnnotation -> com/javacp/annot/TraitAnnotation# +[36:6..36:7): T <- annot/T# +[38:7..38:12): Alias <- annot/Alias. +[39:7..39:8): A <- annot/Alias.A# +[39:11..39:26): ClassAnnotation -> com/javacp/annot/ClassAnnotation# +[39:28..39:33): param -> scala/annotation/meta/param# expect/Anonymous.scala ---------------------- From c54959a28f48d1ca9a2da8d20330a9391ec27ca8 Mon Sep 17 00:00:00 2001 From: Stephane MICHELOUD Date: Sun, 24 Oct 2021 22:24:15 +0200 Subject: [PATCH 0763/1244] small addendum to PR#13790 --- dist/bin/scaladoc.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dist/bin/scaladoc.bat b/dist/bin/scaladoc.bat index 2a80916c1db7..17823d488e56 100644 --- a/dist/bin/scaladoc.bat +++ b/dist/bin/scaladoc.bat @@ -98,7 +98,7 @@ goto :eof @rem output parameter: _CLASS_PATH :classpathArgs -for /f %%f in ("%_PROG_HOME%\.") do set "_LIB_DIR=%%~dpflib" +for /f "delims=" %%f in ("%_PROG_HOME%\.") do set "_LIB_DIR=%%~dpflib" set _CLASS_PATH= @rem keep list in sync with bash script `bin\scaladoc` ! call :updateClasspath "scaladoc" From 5ccc54b1f6e8e75ccbd2ad301d84a1ae42d5d320 Mon Sep 17 00:00:00 2001 From: Kien Dang Date: Wed, 27 Oct 2021 00:31:36 +0800 Subject: [PATCH 0764/1244] No longer print VBAR in the middle of the message Co-authored-by: Tom Grigg --- .../src/dotty/tools/dotc/printing/Texts.scala | 12 +++++++----- .../dotty/tools/dotc/CompilationTests.scala | 1 + tests/neg-custom-args/i13026.check | 18 ++++++++++++++++++ tests/neg-custom-args/i13026.scala | 3 +++ 4 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 tests/neg-custom-args/i13026.check create mode 100644 tests/neg-custom-args/i13026.scala diff --git a/compiler/src/dotty/tools/dotc/printing/Texts.scala b/compiler/src/dotty/tools/dotc/printing/Texts.scala index 7df464ae74b8..9a3aac39ed18 100644 --- a/compiler/src/dotty/tools/dotc/printing/Texts.scala +++ b/compiler/src/dotty/tools/dotc/printing/Texts.scala @@ -106,11 +106,13 @@ object Texts { case Str(s, lines) => if (numberWidth != 0) { val ln = lines.show - val pad = (numberWidth - ln.length - 1) - assert(pad >= 0) - sb.append(" " * pad) - sb.append(ln) - sb.append("|") + if (ln.nonEmpty) { + val pad = (numberWidth - ln.length - 1) + assert(pad >= 0) + sb.append(" " * pad) + sb.append(ln) + sb.append("|") + } } sb.append(s) case _ => diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index a9e679eb6e95..a9f376d3cda6 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -182,6 +182,7 @@ class CompilationTests { compileFile("tests/neg-custom-args/i7314.scala", defaultOptions.and("-Xfatal-warnings", "-source", "future")), compileFile("tests/neg-custom-args/feature-shadowing.scala", defaultOptions.and("-Xfatal-warnings", "-feature")), compileDir("tests/neg-custom-args/hidden-type-errors", defaultOptions.and("-explain")), + compileFile("tests/neg-custom-args/i13026.scala", defaultOptions.and("-print-lines")), ).checkExpectedErrors() } diff --git a/tests/neg-custom-args/i13026.check b/tests/neg-custom-args/i13026.check new file mode 100644 index 000000000000..ec729f1968b1 --- /dev/null +++ b/tests/neg-custom-args/i13026.check @@ -0,0 +1,18 @@ +-- [E007] Type Mismatch Error: tests/neg-custom-args/i13026.scala:1:13 ------------------------------------------------- +1 |val x: Int = "not an int" // error + | ^^^^^^^^^^^^ + | Found: ("not an int" : String) + | Required: Int + +longer explanation available when compiling with `-explain` +-- [E007] Type Mismatch Error: tests/neg-custom-args/i13026.scala:2:13 ------------------------------------------------- +2 |val y: Int = "not an int" // error + | ^^^^^^^^^^^^ + | Found: ("not an int" : String) + | Required: Int + +longer explanation available when compiling with `-explain` +-- [E008] Not Found Error: tests/neg-custom-args/i13026.scala:3:20 ----------------------------------------------------- +3 |def foo(x: Any) = x.foo // error + | ^^^^^ + | value foo is not a member of Any diff --git a/tests/neg-custom-args/i13026.scala b/tests/neg-custom-args/i13026.scala new file mode 100644 index 000000000000..9ecf909f7122 --- /dev/null +++ b/tests/neg-custom-args/i13026.scala @@ -0,0 +1,3 @@ +val x: Int = "not an int" // error +val y: Int = "not an int" // error +def foo(x: Any) = x.foo // error From 35975432852a7b67ca3dc6d34feaaf3797549ee1 Mon Sep 17 00:00:00 2001 From: SDSR Date: Tue, 26 Oct 2021 19:07:49 +0200 Subject: [PATCH 0765/1244] solves dotc assertion error on (non-sensical?) parameter type. #13769 --- compiler/src/dotty/tools/dotc/parsing/Parsers.scala | 3 +++ tests/neg/i13769.check | 10 ++++++++++ tests/neg/i13769.scala | 2 ++ 3 files changed, 15 insertions(+) create mode 100644 tests/neg/i13769.check create mode 100644 tests/neg/i13769.scala diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 44e7145d2ee1..aff7218e662b 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -442,6 +442,9 @@ object Parsers { def convertToParam(tree: Tree, mods: Modifiers, expected: String = "formal parameter"): ValDef = tree match { case id @ Ident(name) => makeParameter(name.asTermName, TypeTree(), mods, isBackquoted = isBackquoted(id)).withSpan(tree.span) + case Typed(_, tpt: TypeBoundsTree) => + syntaxError(s"not a legal $expected", tree.span) + makeParameter(nme.ERROR, tree, mods) case Typed(id @ Ident(name), tpt) => makeParameter(name.asTermName, tpt, mods, isBackquoted = isBackquoted(id)).withSpan(tree.span) case Typed(Splice(Ident(name)), tpt) => diff --git a/tests/neg/i13769.check b/tests/neg/i13769.check new file mode 100644 index 000000000000..7785fbf4d198 --- /dev/null +++ b/tests/neg/i13769.check @@ -0,0 +1,10 @@ +-- Error: tests/neg/i13769.scala:2:18 ---------------------------------------------------------------------------------- +2 |val te = tup.map((x: _ <: Int) => List(x)) // error // error + | ^^^^^^^^^^^ + | not a legal formal parameter +-- [E006] Not Found Error: tests/neg/i13769.scala:2:39 ----------------------------------------------------------------- +2 |val te = tup.map((x: _ <: Int) => List(x)) // error // error + | ^ + | Not found: x + +longer explanation available when compiling with `-explain` \ No newline at end of file diff --git a/tests/neg/i13769.scala b/tests/neg/i13769.scala new file mode 100644 index 000000000000..67575e821334 --- /dev/null +++ b/tests/neg/i13769.scala @@ -0,0 +1,2 @@ +val tup = (1, "s") +val te = tup.map((x: _ <: Int) => List(x)) // error // error From 88e13ec1d37e5eabdc960bdb304c800988411b76 Mon Sep 17 00:00:00 2001 From: Denis Zolkin Date: Tue, 26 Oct 2021 18:32:55 +0200 Subject: [PATCH 0766/1244] Handles Nothing when synthesizing CanEqual fixes #13739 fixes #13512 --- .../dotty/tools/dotc/typer/Synthesizer.scala | 5 +- tests/pos/i13512.scala | 7 +++ tests/pos/i13739.scala | 46 +++++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 tests/pos/i13512.scala create mode 100644 tests/pos/i13739.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala index 75e7c55ada28..2dd088d70671 100644 --- a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala @@ -102,7 +102,8 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context): def canComparePredefinedClasses(cls1: ClassSymbol, cls2: ClassSymbol): Boolean = def cmpWithBoxed(cls1: ClassSymbol, cls2: ClassSymbol) = - cls2 == defn.boxedType(cls1.typeRef).symbol + cls2 == defn.NothingClass + || cls2 == defn.boxedType(cls1.typeRef).symbol || cls1.isNumericValueClass && cls2.derivesFrom(defn.BoxedNumberClass) if cls1.isPrimitiveValueClass then @@ -129,7 +130,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context): else if cls2 == defn.NullClass then cls1.derivesFrom(defn.ObjectClass) else - false + cls1 == defn.NothingClass || cls2 == defn.NothingClass end canComparePredefinedClasses /** Some simulated `CanEqual` instances for predefined types. It's more efficient diff --git a/tests/pos/i13512.scala b/tests/pos/i13512.scala new file mode 100644 index 000000000000..b400809d47b9 --- /dev/null +++ b/tests/pos/i13512.scala @@ -0,0 +1,7 @@ +import scala.language.strictEquality + +class NotEquatable + +def f = List(new NotEquatable) match + case Nil => ??? + case _ => diff --git a/tests/pos/i13739.scala b/tests/pos/i13739.scala new file mode 100644 index 000000000000..418e665f44e8 --- /dev/null +++ b/tests/pos/i13739.scala @@ -0,0 +1,46 @@ +import scala.language.strictEquality + +class Foo(i: Int) extends AnyVal + +val _ = summon[CanEqual[Nothing, Nothing]] + +val _ = summon[CanEqual[Int, Nothing]] +val _ = summon[CanEqual[Nothing, Int]] +val _ = summon[CanEqual[3, Nothing]] +val _ = summon[CanEqual[Nothing, 3]] + +val _ = summon[CanEqual[Byte, Nothing]] +val _ = summon[CanEqual[Nothing, Byte]] +val _ = summon[CanEqual[Short, Nothing]] +val _ = summon[CanEqual[Nothing, Short]] +val _ = summon[CanEqual[Float, Nothing]] +val _ = summon[CanEqual[Nothing, Float]] + +val _ = summon[CanEqual[Double, Nothing]] +val _ = summon[CanEqual[Nothing, Double]] +val _ = summon[CanEqual[3.0, Nothing]] +val _ = summon[CanEqual[Nothing, 3.0]] + +val _ = summon[CanEqual[String, Nothing]] +val _ = summon[CanEqual[Nothing, String]] +val _ = summon[CanEqual["foo", Nothing]] +val _ = summon[CanEqual[Nothing, "foo"]] + +val _ = summon[CanEqual[Char, Nothing]] +val _ = summon[CanEqual[Nothing, Char]] +val _ = summon[CanEqual['f', Nothing]] +val _ = summon[CanEqual[Nothing, 'f']] + +val _ = summon[CanEqual[Boolean, Nothing]] +val _ = summon[CanEqual[Nothing, Boolean]] +val _ = summon[CanEqual[true, Nothing]] +val _ = summon[CanEqual[Nothing, true]] + +val _ = summon[CanEqual[Foo, Nothing]] +val _ = summon[CanEqual[Nothing, Foo]] + +val _ = summon[CanEqual[Option[Int], None.type]] +val _ = summon[CanEqual[Option[Int], Option[Nothing]]] + +val _ = summon[CanEqual[Any & Nothing, Foo]] +val _ = summon[CanEqual[Nothing & Any, Foo]] From 6626c9c6ad2f3ce0392726184faf335452fb5040 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 26 Oct 2021 15:40:51 +0200 Subject: [PATCH 0767/1244] Add explanations to discussion of private[this] in docs Fixes #13770 Or more precisely: it explains the issue with reflection which has been observed in several projects. The issue with WeakReferences is so tricky/underspecified that I did not find a reasonable explanation. I fear people would be confused rather than enlightened. --- .../dropped-features/this-qualifier.md | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/docs/docs/reference/dropped-features/this-qualifier.md b/docs/docs/reference/dropped-features/this-qualifier.md index 69906351ca67..baec0ae454f6 100644 --- a/docs/docs/reference/dropped-features/this-qualifier.md +++ b/docs/docs/reference/dropped-features/this-qualifier.md @@ -12,6 +12,26 @@ Previously, these modifiers were needed for - avoiding the generation of getters and setters - excluding code under a `private[this]` from variance checks. (Scala 2 also excludes `protected[this]` but this was found to be unsound and was therefore removed). + - avoiding the generation of fields, if a `private[this] val` is not accessed + by a class method. The compiler now infers for `private` members the fact that they are only accessed via `this`. Such members are treated as if they had been declared `private[this]`. `protected[this]` is dropped without a replacement. +This change can in some cases change the semantics of a Scala program, since a +`private` val is no longer guaranteed to generate a field. The field +is omitted if + + - the `val` is only accessed via `this`, and + - the `val` is not accessed from a method in the current class. + +This can cause problems if a program tries to access the missing private field via reflection. The recommended fix is to declare the field instead to be qualified private with the enclosing class as qualifier. Example: +```scala + class C(x: Int): + private[C] val field = x + 1 + // [C] needed if `field` is to be accessed through reflection + val retained = field * field +``` + + + + From 5fcb34b12569666ff7e3f88676be1828cbdf8841 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 27 Oct 2021 10:29:30 +0200 Subject: [PATCH 0768/1244] Add type class power macro regression test --- tests/pos-macros/power-macro-2/Macro_1.scala | 22 +++++++++++++++++ tests/pos-macros/power-macro-2/Test_2.scala | 2 ++ tests/pos-macros/power-macro-3/Macro_1.scala | 25 ++++++++++++++++++++ tests/pos-macros/power-macro-3/Test_2.scala | 2 ++ 4 files changed, 51 insertions(+) create mode 100644 tests/pos-macros/power-macro-2/Macro_1.scala create mode 100644 tests/pos-macros/power-macro-2/Test_2.scala create mode 100644 tests/pos-macros/power-macro-3/Macro_1.scala create mode 100644 tests/pos-macros/power-macro-3/Test_2.scala diff --git a/tests/pos-macros/power-macro-2/Macro_1.scala b/tests/pos-macros/power-macro-2/Macro_1.scala new file mode 100644 index 000000000000..57f7764f0969 --- /dev/null +++ b/tests/pos-macros/power-macro-2/Macro_1.scala @@ -0,0 +1,22 @@ + +import scala.quoted.* + +import math.Numeric.Implicits.infixNumericOps + +inline def power[Num](x: Num, inline n: Int)(using num: Numeric[Num]) = ${powerCode('x, 'n)(using 'num)} + +private def powerCode[Num: Type](x: Expr[Num], n: Expr[Int])(using Expr[Numeric[Num]])(using Quotes): Expr[Num] = + powerCode(x, n.valueOrAbort) + +private def powerCode[Num: Type](x: Expr[Num], n: Int)(using num: Expr[Numeric[Num]])(using Quotes): Expr[Num] = + if (n == 0) '{ $num.one } + else if (n % 2 == 0) '{ + given Numeric[Num] = $num + val y = $x * $x + ${ powerCode('y, n / 2) } + } + else '{ + given Numeric[Num] = $num + $x * ${powerCode(x, n - 1)} + } + diff --git a/tests/pos-macros/power-macro-2/Test_2.scala b/tests/pos-macros/power-macro-2/Test_2.scala new file mode 100644 index 000000000000..59644c3d51fb --- /dev/null +++ b/tests/pos-macros/power-macro-2/Test_2.scala @@ -0,0 +1,2 @@ +def test(x: Int) = power(x, 5) +def test(x: Double) = power(x, 5) diff --git a/tests/pos-macros/power-macro-3/Macro_1.scala b/tests/pos-macros/power-macro-3/Macro_1.scala new file mode 100644 index 000000000000..d8273c65faf8 --- /dev/null +++ b/tests/pos-macros/power-macro-3/Macro_1.scala @@ -0,0 +1,25 @@ + +import scala.quoted.* + +import math.Numeric.Implicits.infixNumericOps + +inline def power[Num](x: Num, inline n: Int)(using num: Numeric[Num]) = ${powerCode('x, 'n)(using 'num)} + +private def powerCode[Num: Type](x: Expr[Num], n: Expr[Int])(using Expr[Numeric[Num]])(using Quotes): Expr[Num] = + powerCode(x, n.valueOrAbort) + +private def powerCode[Num: Type](x: Expr[Num], n: Int)(using num: Expr[Numeric[Num]])(using Quotes): Expr[Num] = + if (n == 0) '{ $num.one } + else if (n % 2 == 0) '{ + withGiven($num) { + val y = $x * $x + ${ powerCode('y, n / 2) } + } + } + else '{ + withGiven($num) { + $x * ${powerCode(x, n - 1)} + } + } + +inline def withGiven[U, T](inline x: T)(inline body: T ?=> U): U = body(using x) diff --git a/tests/pos-macros/power-macro-3/Test_2.scala b/tests/pos-macros/power-macro-3/Test_2.scala new file mode 100644 index 000000000000..59644c3d51fb --- /dev/null +++ b/tests/pos-macros/power-macro-3/Test_2.scala @@ -0,0 +1,2 @@ +def test(x: Int) = power(x, 5) +def test(x: Double) = power(x, 5) From c489efe887c1b180dd76b6bac0d681d970d6b65c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Zyba=C5=82a?= Date: Tue, 26 Oct 2021 10:37:40 +0200 Subject: [PATCH 0769/1244] Scaladoc: Fix locations of members with slashes --- .../externalLocations/externalStubs.scala | 5 +++++ .../tests/externalLocations/scaladoc2.scala | 6 +++++- .../tests/externalLocations/scaladoc3.scala | 6 +++++- .../src/tests/slashMembers.scala | 8 ++++++++ .../tools/scaladoc/renderers/Locations.scala | 1 + .../dotty/tools/scaladoc/tasty/SymOps.scala | 2 +- .../src/dotty/tools/scaladoc/util/escape.scala | 9 ++++++++- ...ternalLocationProviderIntegrationTest.scala | 18 ++++++++++++++---- 8 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 scaladoc-testcases/src/tests/externalLocations/externalStubs.scala create mode 100644 scaladoc-testcases/src/tests/slashMembers.scala diff --git a/scaladoc-testcases/src/tests/externalLocations/externalStubs.scala b/scaladoc-testcases/src/tests/externalLocations/externalStubs.scala new file mode 100644 index 000000000000..01eb2fbc3a3f --- /dev/null +++ b/scaladoc-testcases/src/tests/externalLocations/externalStubs.scala @@ -0,0 +1,5 @@ +package tests.externalStubs + +trait \/ + +trait /\ \ No newline at end of file diff --git a/scaladoc-testcases/src/tests/externalLocations/scaladoc2.scala b/scaladoc-testcases/src/tests/externalLocations/scaladoc2.scala index b7d024ff5eb4..3319b1ab4e90 100644 --- a/scaladoc-testcases/src/tests/externalLocations/scaladoc2.scala +++ b/scaladoc-testcases/src/tests/externalLocations/scaladoc2.scala @@ -1,6 +1,8 @@ -package tests.externalScaladoc2 +package tests +package externalScaladoc2 import scala.util.matching.* +import externalStubs._ class Test { def a: String = ??? @@ -10,5 +12,7 @@ class Test { def c: Regex.Match = ??? } +class Test2 extends \/ with /\ + abstract class MySeq[T] extends scala.collection.immutable.Seq[T] diff --git a/scaladoc-testcases/src/tests/externalLocations/scaladoc3.scala b/scaladoc-testcases/src/tests/externalLocations/scaladoc3.scala index 590c19ffaa6c..0eb8c7318d75 100644 --- a/scaladoc-testcases/src/tests/externalLocations/scaladoc3.scala +++ b/scaladoc-testcases/src/tests/externalLocations/scaladoc3.scala @@ -1,6 +1,8 @@ -package tests.externalScaladoc3 +package tests +package externalScaladoc3 import scala.util.matching.* +import externalStubs._ class Test { def a: String = ??? @@ -10,3 +12,5 @@ class Test { def c: Regex.Match = ??? } +class Test2 extends \/ with /\ + diff --git a/scaladoc-testcases/src/tests/slashMembers.scala b/scaladoc-testcases/src/tests/slashMembers.scala new file mode 100644 index 000000000000..f13e36f82aae --- /dev/null +++ b/scaladoc-testcases/src/tests/slashMembers.scala @@ -0,0 +1,8 @@ +package tests +package slashMembers + +class A + +trait \/ + +trait /\ \ No newline at end of file diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala index 81baf34b778e..bcdaa2bb5a5a 100644 --- a/scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala @@ -13,6 +13,7 @@ import java.nio.file.Path import java.nio.file.Files import java.io.File import scala.util.matching._ +import dotty.tools.scaladoc.util.Escape._ val UnresolvedLocationLink = "#" diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala index fbccedf9a7eb..5a245a3301f4 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala @@ -261,7 +261,7 @@ class SymOpsWithLinkCache: else (sym.className, sym.anchor) - val location = sym.packageNameSplitted ++ className + val location = (sym.packageNameSplitted ++ className).map(escapeFilename(_)) val externalLink = { import reflect._ diff --git a/scaladoc/src/dotty/tools/scaladoc/util/escape.scala b/scaladoc/src/dotty/tools/scaladoc/util/escape.scala index 66035e76ca98..686d384337c1 100644 --- a/scaladoc/src/dotty/tools/scaladoc/util/escape.scala +++ b/scaladoc/src/dotty/tools/scaladoc/util/escape.scala @@ -1,4 +1,11 @@ package dotty.tools.scaladoc.util object Escape: - def escapeUrl(url: String) = url.replace("#","%23") \ No newline at end of file + def escapeUrl(url: String) = url + .replace("#","%23") + + def escapeFilename(filename: String) = + val escaped = filename + .replace("/", "$div") + .replace("\\", "$bslash") + if escaped != filename then escaped + "$" else escaped diff --git a/scaladoc/test/dotty/tools/scaladoc/ExternalLocationProviderIntegrationTest.scala b/scaladoc/test/dotty/tools/scaladoc/ExternalLocationProviderIntegrationTest.scala index 2ca6f28ffd27..4f4f8c972b4e 100644 --- a/scaladoc/test/dotty/tools/scaladoc/ExternalLocationProviderIntegrationTest.scala +++ b/scaladoc/test/dotty/tools/scaladoc/ExternalLocationProviderIntegrationTest.scala @@ -25,23 +25,33 @@ class JavadocExternalLocationProviderIntegrationTest extends ExternalLocationPro class Scaladoc2ExternalLocationProviderIntegrationTest extends ExternalLocationProviderIntegrationTest( "externalScaladoc2", - List(".*scala.*::scaladoc2::https://www.scala-lang.org/api/current/"), + List( + ".*scala/.*::scaladoc2::https://www.scala-lang.org/api/current/", + ".*externalStubs.*::scaladoc2::https://external.stubs/api/" + ), List( "https://www.scala-lang.org/api/current/scala/util/matching/Regex$$Match.html", "https://www.scala-lang.org/api/current/scala/Predef$.html#String", "https://www.scala-lang.org/api/current/scala/collection/immutable/Map.html", "https://www.scala-lang.org/api/current/scala/collection/IterableOnceOps.html#addString(b:StringBuilder,start:String,sep:String,end:String):StringBuilder", - "https://www.scala-lang.org/api/current/scala/collection/IterableOnceOps.html#mkString(start:String,sep:String,end:String):String" + "https://www.scala-lang.org/api/current/scala/collection/IterableOnceOps.html#mkString(start:String,sep:String,end:String):String", + "https://external.stubs/api/tests/externalStubs/$div$bslash$.html", + "https://external.stubs/api/tests/externalStubs/$bslash$div$.html" ) ) class Scaladoc3ExternalLocationProviderIntegrationTest extends ExternalLocationProviderIntegrationTest( "externalScaladoc3", - List(".*scala.*::scaladoc3::https://dotty.epfl.ch/api/"), + List( + ".*scala/.*::scaladoc3::https://dotty.epfl.ch/api/", + ".*externalStubs.*::scaladoc3::https://external.stubs/api/" + ), List( "https://dotty.epfl.ch/api/scala/collection/immutable/Map.html", "https://dotty.epfl.ch/api/scala/Predef$.html#String-0", - "https://dotty.epfl.ch/api/scala/util/matching/Regex$$Match.html" + "https://dotty.epfl.ch/api/scala/util/matching/Regex$$Match.html", + "https://external.stubs/api/tests/externalStubs/$div$bslash$.html", + "https://external.stubs/api/tests/externalStubs/$bslash$div$.html" ) ) From d229f5d225b7324d13a9f50b5272144361d3642c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Zyba=C5=82a?= Date: Tue, 26 Oct 2021 16:43:00 +0200 Subject: [PATCH 0770/1244] Scaladoc: Fix given signatures --- .../src/tests/givenSignatures.scala | 10 ++- .../src/tests/inheritedMembers1.scala | 6 +- scaladoc/src/dotty/tools/scaladoc/api.scala | 2 +- .../scaladoc/tasty/ClassLikeSupport.scala | 64 ++++--------------- .../tools/scaladoc/tasty/NameNormalizer.scala | 16 ++--- .../dotty/tools/scaladoc/tasty/SymOps.scala | 2 - .../tools/scaladoc/tasty/TypesSupport.scala | 2 +- .../translators/ScalaSignatureProvider.scala | 18 +++++- .../scaladoc/signatures/SignatureTest.scala | 26 ++++---- 9 files changed, 65 insertions(+), 81 deletions(-) diff --git a/scaladoc-testcases/src/tests/givenSignatures.scala b/scaladoc-testcases/src/tests/givenSignatures.scala index a1143e908da9..ff447ffc4553 100644 --- a/scaladoc-testcases/src/tests/givenSignatures.scala +++ b/scaladoc-testcases/src/tests/givenSignatures.scala @@ -4,9 +4,9 @@ package givenSignatures object Obj -given Seq[String] = Nil +given Seq[String] = Nil //expected: given given_Seq_String: Seq[String] -given GivenType = GivenType() +given GivenType = GivenType() //expected: given given_GivenType: GivenType class GivenType @@ -14,3 +14,9 @@ trait Ord[T] given listOrd[T](using ord: Ord[T]): Ord[List[T]] = ??? + +trait Foo[A] + +given listOrd: Foo[String] with { val i: Int = 1 } //expected: given listOrd: listOrd.type + +trait Placeholder //expected: object listOrd extends Foo[String] diff --git a/scaladoc-testcases/src/tests/inheritedMembers1.scala b/scaladoc-testcases/src/tests/inheritedMembers1.scala index 6a86c523bd19..d8fa44607e5e 100644 --- a/scaladoc-testcases/src/tests/inheritedMembers1.scala +++ b/scaladoc-testcases/src/tests/inheritedMembers1.scala @@ -10,7 +10,11 @@ class A = ??? object X trait Z - given B with {} + given B with { val x = 1 }//expected: given given_B: given_B.type + trait Placeholder//expected: object given_B extends B + + object Y extends Z + type I = Int /*<-*/extension (a: A) /*->*/def extension: String = ??? diff --git a/scaladoc/src/dotty/tools/scaladoc/api.scala b/scaladoc/src/dotty/tools/scaladoc/api.scala index fbe0f455c794..f7285a9da6ec 100644 --- a/scaladoc/src/dotty/tools/scaladoc/api.scala +++ b/scaladoc/src/dotty/tools/scaladoc/api.scala @@ -67,7 +67,7 @@ enum Kind(val name: String): case Exported(m: Kind.Def) extends Kind("export") case Type(concreate: Boolean, opaque: Boolean, typeParams: Seq[TypeParameter]) extends Kind("type") // should we handle opaque as modifier? - case Given(kind: Def | Class, as: Option[Signature], conversion: Option[ImplicitConversion]) + case Given(kind: Def | Class | Val.type, as: Option[Signature], conversion: Option[ImplicitConversion]) extends Kind("given") with ImplicitConversionProvider case Implicit(kind: Kind.Def | Kind.Val.type, conversion: Option[ImplicitConversion]) extends Kind(kind.name) with ImplicitConversionProvider diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala index de3cb429922b..d64aa8d67874 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala @@ -97,15 +97,16 @@ trait ClassLikeSupport: val baseMember = mkMember(classDef.symbol, kindForClasslike(classDef), selfSignature)( modifiers = modifiers, graph = graph, - deprecated = classDef.symbol.isDeprecated() + deprecated = classDef.symbol.isDeprecated(), + ).copy( + directParents = classDef.getParentsAsLinkToTypes, + parents = supertypes, ) if summon[DocContext].args.generateInkuire then doInkuireStuff(classDef) if signatureOnly then baseMember else baseMember.copy( members = classDef.extractPatchedMembers.sortBy(m => (m.name, m.kind.name)), - directParents = classDef.getParentsAsLinkToTypes, - parents = supertypes, selfType = selfType, companion = classDef.getCompanion ) @@ -144,15 +145,6 @@ trait ClassLikeSupport: ) parseMethod(c, dd.symbol,specificKind = Kind.Extension(target, _)) } - // TODO check given methods? - case dd: DefDef if !dd.symbol.isHiddenByVisibility && dd.symbol.isGiven && !dd.symbol.isArtifact => - Some(dd.symbol.owner.typeMember(dd.name)) - .filterNot(_.exists) - .map { _ => - parseMethod(c, dd.symbol, specificKind = - Kind.Given(_, getGivenInstance(dd), None) - ) - } case dd: DefDef if !dd.symbol.isHiddenByVisibility && dd.symbol.isExported && !dd.symbol.isArtifact => val exportedTarget = dd.rhs.collect { @@ -171,58 +163,25 @@ trait ClassLikeSupport: Some(parseMethod(c, dd.symbol, specificKind = Kind.Exported(_)) .withOrigin(Origin.ExportedFrom(s"$instanceName.$functionName", dri))) - case dd: DefDef if !dd.symbol.isHiddenByVisibility && !dd.symbol.isGiven && !dd.symbol.isSyntheticFunc && !dd.symbol.isExtensionMethod && !dd.symbol.isArtifact => + case dd: DefDef if !dd.symbol.isHiddenByVisibility && !dd.symbol.isSyntheticFunc && !dd.symbol.isExtensionMethod && !dd.symbol.isArtifact => Some(parseMethod(c, dd.symbol)) case td: TypeDef if !td.symbol.flags.is(Flags.Synthetic) && (!td.symbol.flags.is(Flags.Case) || !td.symbol.flags.is(Flags.Enum)) => Some(parseTypeDef(td)) - case vd: ValDef if !isSyntheticField(vd.symbol) - && (!vd.symbol.flags.is(Flags.Case) || !vd.symbol.flags.is(Flags.Enum)) - && vd.symbol.isGiven => - val classDef = Some(vd.tpt.tpe).flatMap(_.classSymbol.map(_.tree.asInstanceOf[ClassDef])) - Some(classDef.filter(_.symbol.flags.is(Flags.Module)).fold[Member](parseValDef(c, vd))(parseGivenClasslike(_))) - case vd: ValDef if !isSyntheticField(vd.symbol) && (!vd.symbol.flags.is(Flags.Case) || !vd.symbol.flags.is(Flags.Enum)) => Some(parseValDef(c, vd)) - case c: ClassDef if c.symbol.owner.methodMember(c.name).exists(_.flags.is(Flags.Given)) => - Some(parseGivenClasslike(c)) - - case c: ClassDef if c.symbol.shouldDocumentClasslike && !c.symbol.isGiven => + case c: ClassDef if c.symbol.shouldDocumentClasslike => Some(parseClasslike(c)) case _ => None } - private def parseGivenClasslike(c: ClassDef): Member = { - val parsedClasslike = parseClasslike(c) - - val parentTpe = c.parents(0) match { - case t: TypeTree => Some(t.tpe) - case t: Term => Some(t.tpe) - case _ => None - } - - val givenParents = parsedClasslike.directParents.headOption - val cls: Kind.Class = parsedClasslike.kind match - case Kind.Object => Kind.Class(Nil, Nil) - case Kind.Trait(tps, args) => Kind.Class(tps, args) - case cls: Kind.Class => cls - case other => - report.warning("Unrecoginzed kind for given: $other", c.pos) - Kind.Class(Nil, Nil) - - parsedClasslike.withKind( - Kind.Given(cls, givenParents.map(_.signature), parentTpe.flatMap(extractImplicitConversion)) - ) - } - private def parseInheritedMember(c: ClassDef)(s: Tree): Option[Member] = def inheritance = Some(InheritedFrom(s.symbol.owner.normalizedName, s.symbol.dri)) processTreeOpt(s)(s match - case c: ClassDef if c.symbol.shouldDocumentClasslike && !c.symbol.isGiven => Some(parseClasslike(c, signatureOnly = true)) - case c: ClassDef if c.symbol.owner.methodMember(c.name).exists(_.flags.is(Flags.Given)) => Some(parseGivenClasslike(c)) + case c: ClassDef if c.symbol.shouldDocumentClasslike => Some(parseClasslike(c, signatureOnly = true)) case other => { val parsed = parseMember(c)(other) parsed.map(p => @@ -395,6 +354,7 @@ trait ClassLikeSupport: )) case _ => Kind.Implicit(basicKind, None) + else if methodSymbol.flags.is(Flags.Given) then Kind.Given(basicKind, Some(method.returnTpt.tpe.asSignature), extractImplicitConversion(method.returnTpt.tpe)) else specificKind(basicKind) val origin = if !methodSymbol.isOverridden then Origin.RegularlyDefined else @@ -466,10 +426,10 @@ trait ClassLikeSupport: def parseValDef(c: ClassDef, valDef: ValDef): Member = def defaultKind = if valDef.symbol.flags.is(Flags.Mutable) then Kind.Var else Kind.Val val memberInfo = unwrapMemberInfo(c, valDef.symbol) - val kind = if valDef.symbol.flags.is(Flags.Implicit) then - Kind.Implicit(Kind.Val, extractImplicitConversion(valDef.tpt.tpe)) - else if valDef.symbol.flags.is(Flags.Enum) then Kind.EnumCase(Kind.Val) - else defaultKind + val kind = if valDef.symbol.flags.is(Flags.Implicit) then Kind.Implicit(Kind.Val, extractImplicitConversion(valDef.tpt.tpe)) + else if valDef.symbol.flags.is(Flags.Given) then Kind.Given(Kind.Val, Some(memberInfo.res.asSignature), extractImplicitConversion(valDef.tpt.tpe)) + else if valDef.symbol.flags.is(Flags.Enum) then Kind.EnumCase(Kind.Val) + else defaultKind mkMember(valDef.symbol, kind, memberInfo.res.asSignature)(deprecated = valDef.symbol.isDeprecated()) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/NameNormalizer.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/NameNormalizer.scala index 6ba4e3f3ff36..687ad6ecbf44 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/NameNormalizer.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/NameNormalizer.scala @@ -9,14 +9,14 @@ import SymOps._ object NameNormalizer { - extension (using Quotes)(s: reflect.Symbol) def normalizedName: String = { - import reflect.* - val withoutGivenPrefix = if s.isGiven then s.name.stripPrefix("given_") else s.name - val withoutObjectSuffix = if s.flags.is(Flags.Module) then withoutGivenPrefix.stripSuffix("$") else withoutGivenPrefix - val constructorNormalizedName = if s.isClassConstructor then "this" else withoutObjectSuffix - val escaped = escapedName(constructorNormalizedName) - escaped - } + extension (using Quotes)(s: reflect.Symbol) + def normalizedName: String = { + import reflect.* + val withoutObjectSuffix = if s.flags.is(Flags.Module) then s.name.stripSuffix("$") else s.name + val constructorNormalizedName = if s.isClassConstructor then "this" else withoutObjectSuffix + val escaped = escapedName(constructorNormalizedName) + escaped + } private val ignoredKeywords: Set[String] = Set("this") diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala index 5a245a3301f4..6e80c164d1d9 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala @@ -115,7 +115,6 @@ object SymOps: !sym.isHiddenByVisibility && !sym.flags.is(Flags.Synthetic) && (!sym.flags.is(Flags.Case) || !sym.flags.is(Flags.Enum)) - && !(sym.companionModule.flags.is(Flags.Given)) def getCompanionSymbol: Option[reflect.Symbol] = Some(sym.companionClass).filter(_.exists) @@ -249,7 +248,6 @@ class SymOpsWithLinkCache: def dri(using dctx: DocContext): DRI = import reflect.* if sym == Symbol.noSymbol then topLevelDri - else if sym.isValDef && sym.moduleClass.exists then sym.moduleClass.dri else val method = if (sym.isDefDef) Some(sym) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/TypesSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/TypesSupport.scala index d4907138c233..147b5c40d21b 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/TypesSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/TypesSupport.scala @@ -61,7 +61,7 @@ trait TypesSupport: extension (on: SignaturePart) def l: List[SignaturePart] = List(on) private def tpe(using Quotes)(symbol: reflect.Symbol): SSignature = - val suffix = if symbol.isValDef then plain(".type").l else Nil + val suffix = if symbol.isValDef || symbol.flags.is(reflect.Flags.Module) then plain(".type").l else Nil dotty.tools.scaladoc.Type(symbol.normalizedName, Some(symbol.dri)) :: suffix private def commas(lists: List[SSignature]) = lists match diff --git a/scaladoc/src/dotty/tools/scaladoc/translators/ScalaSignatureProvider.scala b/scaladoc/src/dotty/tools/scaladoc/translators/ScalaSignatureProvider.scala index 8bd0a571b7d7..d8f80f332b6d 100644 --- a/scaladoc/src/dotty/tools/scaladoc/translators/ScalaSignatureProvider.scala +++ b/scaladoc/src/dotty/tools/scaladoc/translators/ScalaSignatureProvider.scala @@ -22,6 +22,8 @@ object ScalaSignatureProvider: givenClassSignature(documentable, cls, builder) case Kind.Given(d: Kind.Def, _, _) => givenMethodSignature(documentable, d, builder) + case Kind.Given(Kind.Val, _, _) => + givenValSignature(documentable, builder) case cls: Kind.Class => classSignature(documentable, cls, builder) case enm: Kind.Enum => @@ -129,10 +131,24 @@ object ScalaSignatureProvider: case Kind.Given(_, Some(instance), _) => builder.keyword("given ") .name(method.name, method.dri) + .generics(body.typeParams) + .functionParameters(body.argsLists) .plain(": ") .signature(instance) case _ => - builder.keyword("given ").name(method.name, method.dri) + builder.keyword("given ") + .name(method.name, method.dri) + .generics(body.typeParams) + .functionParameters(body.argsLists) + + private def givenValSignature(field: Member, builder: SignatureBuilder): SignatureBuilder = field.kind match + case Kind.Given(_, Some(instance), _) => + builder.keyword("given ") + .name(field.name, field.dri) + .plain(": ") + .signature(instance) + case _ => + builder.keyword("given ").name(field.name, field.dri) private def methodSignature(method: Member, cls: Kind.Def, builder: SignatureBuilder): SignatureBuilder = val bdr = builder diff --git a/scaladoc/test/dotty/tools/scaladoc/signatures/SignatureTest.scala b/scaladoc/test/dotty/tools/scaladoc/signatures/SignatureTest.scala index ebd53db8c77e..4d8a9f46f21e 100644 --- a/scaladoc/test/dotty/tools/scaladoc/signatures/SignatureTest.scala +++ b/scaladoc/test/dotty/tools/scaladoc/signatures/SignatureTest.scala @@ -91,18 +91,18 @@ abstract class SignatureTest( private def signaturesFromSources(source: Source, kinds: Seq[String]): Seq[SignatureRes] = source.getLines.map(_.trim) - .filterNot(_.isEmpty) - .filterNot(_.startWithAnyOfThese("=",":","{","}", "//")) - .toSeq - .flatMap { - case unexpectedRegex(signature) => findName(signature, kinds).map(Unexpected(_)) - case expectedRegex(signature) => findName(signature, kinds).map(Expected(_, signature)) - case signature => - findName(signature, kinds).map( - Expected(_, commentRegex.replaceAllIn(signature, "") - .compactWhitespaces.reverse.dropWhile(List('{', ':').contains(_)).reverse) - ) - } + .filterNot(_.isEmpty) + .filterNot(_.startWithAnyOfThese("=",":","{","}", "//")) + .toSeq + .flatMap { + case unexpectedRegex(signature) => findName(signature, kinds).map(Unexpected(_)) + case expectedRegex(signature) => findName(signature, kinds).map(Expected(_, signature)) + case signature => + findName(signature, kinds).map( + Expected(_, commentRegex.replaceAllIn(signature, "") + .compactWhitespaces.reverse.dropWhile(List('{', ':').contains(_)).reverse) + ) + } private def signaturesFromDocumentation()(using DocContext): Seq[String] = val output = summon[DocContext].args.output.toPath @@ -129,6 +129,6 @@ abstract class SignatureTest( object SignatureTest { val classlikeKinds = Seq("class", "object", "trait", "enum") // TODO add docs for packages - val members = Seq("type", "def", "val", "var") + val members = Seq("type", "def", "val", "var", "given") val all = classlikeKinds ++ members } From b9e8a99ba692a8e1950394e452b5fc34356affe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Zyba=C5=82a?= Date: Tue, 26 Oct 2021 18:09:15 +0200 Subject: [PATCH 0771/1244] Scaladoc: Update list of unsupported settings --- scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala b/scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala index 4697783de20c..e6e32ec475d5 100644 --- a/scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala +++ b/scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala @@ -18,12 +18,8 @@ import dotty.tools.dotc.core.Contexts._ class ScaladocSettings extends SettingGroup with AllScalaSettings: val unsupportedSettings = Seq( - // Options that we like to support - extdirs, javabootclasspath, encoding, // Needed for plugin architecture - plugin,disable,require, pluginsDir, pluginOptions, - // we need support for sourcepath and sourceroot - sourcepath, sourceroot + plugin, disable, require, pluginsDir, pluginOptions, ) From 78db40aa7c2d337df4438c126a40c80879a605b1 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Wed, 27 Oct 2021 16:46:19 +0200 Subject: [PATCH 0772/1244] Navigate the AST within AnnotatedType and ImportType Related to https://github.com/lampepfl/dotty/issues/13624 --- .../dotty/tools/dotc/ast/NavigateAST.scala | 23 ++++++++++++++++++- .../tools/languageserver/CompletionTest.scala | 19 ++++++++++++++- .../tools/languageserver/HoverTest.scala | 8 +++++-- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/NavigateAST.scala b/compiler/src/dotty/tools/dotc/ast/NavigateAST.scala index ffc7d04faa52..61561d5eaa24 100644 --- a/compiler/src/dotty/tools/dotc/ast/NavigateAST.scala +++ b/compiler/src/dotty/tools/dotc/ast/NavigateAST.scala @@ -5,6 +5,10 @@ import core.Contexts._ import core.Decorators._ import util.Spans._ import Trees.{MemberDef, DefTree, WithLazyField} +import dotty.tools.dotc.core.Annotations.ConcreteAnnotation +import dotty.tools.dotc.core.Types.AnnotatedType +import dotty.tools.dotc.core.Types.ImportType +import dotty.tools.dotc.core.Types.Type /** Utility functions to go from typed to untyped ASTs */ // TODO: Handle trees with mixed source files @@ -86,6 +90,18 @@ object NavigateAST { } bestFit } + /* + * Annotations trees are located in the Type + */ + def unpackAnnotations(t: Type, path: List[Positioned]): List[Positioned] = + t match { + case ann: AnnotatedType => + unpackAnnotations(ann.parent, childPath(ann.annot.tree.productIterator, path)) + case imp: ImportType => + childPath(imp.expr.productIterator, path) + case other => + path + } def singlePath(p: Positioned, path: List[Positioned]): List[Positioned] = if (p.span.exists && !(skipZeroExtent && p.span.isZeroExtent) && p.span.contains(span)) { // FIXME: We shouldn't be manually forcing trees here, we should replace @@ -98,7 +114,12 @@ object NavigateAST { } childPath(p.productIterator, p :: path) } - else path + else { + p match { + case t: untpd.TypeTree => unpackAnnotations(t.typeOpt, path) + case _ => path + } + } singlePath(from, Nil) } } diff --git a/language-server/test/dotty/tools/languageserver/CompletionTest.scala b/language-server/test/dotty/tools/languageserver/CompletionTest.scala index 7e71c0a4c2b1..26b5d51993b9 100644 --- a/language-server/test/dotty/tools/languageserver/CompletionTest.scala +++ b/language-server/test/dotty/tools/languageserver/CompletionTest.scala @@ -895,4 +895,21 @@ class CompletionTest { @Test def i12465_hkt_alias: Unit = code"""???.asInstanceOf[Seq].${m1}""".withSource .completion(m1, Set()) -} + + @Test def i13624_annotType: Unit = + code"""|class MyAnnotation extends annotation.StaticAnnotation + |val x = 1: @MyAnnot${m1} + |type X = Int @MyAnnot${m2}""".withSource + .completion( + m1, + Set( + ("MyAnnotation", Class, "MyAnnotation"), + ("MyAnnotation", Module, "MyAnnotation") + ) + ).completion( + m2, + Set( + ("MyAnnotation", Class, "MyAnnotation"), + ("MyAnnotation", Module, "MyAnnotation") + ) + )} diff --git a/language-server/test/dotty/tools/languageserver/HoverTest.scala b/language-server/test/dotty/tools/languageserver/HoverTest.scala index 54d3271f2565..4309b0aeeea0 100644 --- a/language-server/test/dotty/tools/languageserver/HoverTest.scala +++ b/language-server/test/dotty/tools/languageserver/HoverTest.scala @@ -177,7 +177,7 @@ class HoverTest { @Test def i4678: Unit = { code"""class Foo { - | val x: Int = (${m1}1:${m2} ${m3}@annot1 @annot2 @annot3 @annot4 @annot5${m4}) + | val x: Int = (${m1}1:${m2} ${m3}@annot1${m4} ${m5}@annot2${m6} ${m7}@annot3${m8} ${m9}@annot4${m10} ${m11}@annot5${m12}) |} |class annot1 extends scala.annotation.Annotation |class annot2 extends scala.annotation.Annotation @@ -186,7 +186,11 @@ class HoverTest { |class annot5 extends scala.annotation.Annotation |""".withSource .hover(m1 to m2, hoverContent("(1 : Int)")) - .hover(m3 to m4, hoverContent("(1 : Int) @annot1 @annot2 @annot3 @annot4 @annot5")) + .hover(m3 to m4, hoverContent("annot1")) + .hover(m5 to m6, hoverContent("annot2")) + .hover(m7 to m8, hoverContent("annot3")) + .hover(m9 to m10, hoverContent("annot4")) + .hover(m11 to m12, hoverContent("annot5")) } @Test def unicodeChar: Unit = { From 81e876a6056e4d829550f975cd6d0880c81381b8 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Thu, 28 Oct 2021 18:54:07 +0200 Subject: [PATCH 0773/1244] Add additional test for annotation completions --- .../tools/languageserver/CompletionTest.scala | 40 +++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/language-server/test/dotty/tools/languageserver/CompletionTest.scala b/language-server/test/dotty/tools/languageserver/CompletionTest.scala index 26b5d51993b9..1dd9516de7d1 100644 --- a/language-server/test/dotty/tools/languageserver/CompletionTest.scala +++ b/language-server/test/dotty/tools/languageserver/CompletionTest.scala @@ -897,9 +897,18 @@ class CompletionTest { .completion(m1, Set()) @Test def i13624_annotType: Unit = - code"""|class MyAnnotation extends annotation.StaticAnnotation + code"""|object Foo{ + | class MyAnnotation extends annotation.StaticAnnotation + |} + |class MyAnnotation extends annotation.StaticAnnotation + |class Annotation2(a: String) extends annotation.StaticAnnotation |val x = 1: @MyAnnot${m1} - |type X = Int @MyAnnot${m2}""".withSource + |type X = Int @MyAnnot${m2} + |val y = 1: @Foo.MyAnnot${m3} + |val z = 1: @Foo.MyAnnotation @MyAnno${m4} + |type Y = Int @MyAnnotation @Foo.MyAnnota${m5} + |val w = 1: @Annotation2("abc": @Foo.MyAnnot${m6}) + |""".withSource .completion( m1, Set( @@ -912,4 +921,29 @@ class CompletionTest { ("MyAnnotation", Class, "MyAnnotation"), ("MyAnnotation", Module, "MyAnnotation") ) - )} + ).completion( + m3, + Set( + ("MyAnnotation", Class, "Foo.MyAnnotation"), + ("MyAnnotation", Module, "Foo.MyAnnotation") + ) + ).completion( + m4, + Set( + ("MyAnnotation", Class, "MyAnnotation"), + ("MyAnnotation", Module, "MyAnnotation") + ) + ).completion( + m5, + Set( + ("MyAnnotation", Class, "Foo.MyAnnotation"), + ("MyAnnotation", Module, "Foo.MyAnnotation") + ) + ).completion( + m6, + Set( + ("MyAnnotation", Class, "Foo.MyAnnotation"), + ("MyAnnotation", Module, "Foo.MyAnnotation") + ) + ) +} From fdad2b8036ff74b1920fcf4e8cd74226659684d1 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Wed, 27 Oct 2021 02:08:48 -0400 Subject: [PATCH 0774/1244] Fix comparing AnyVal | Null with Null --- .../src/dotty/tools/dotc/core/Types.scala | 19 ++++++++++++------- .../src/dotty/tools/dotc/typer/Typer.scala | 2 +- tests/explicit-nulls/pos/AnyValOrNull.scala | 16 ++++++++++++++++ 3 files changed, 29 insertions(+), 8 deletions(-) create mode 100644 tests/explicit-nulls/pos/AnyValOrNull.scala diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 6650771963f9..ae7ec91e7108 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -853,18 +853,23 @@ object Types { def goAnd(l: Type, r: Type) = go(l).meet(go(r), pre, safeIntersection = ctx.base.pendingMemberSearches.contains(name)) - def goOr(tp: OrType) = tp match { - case OrNull(tp1) if Nullables.unsafeNullsEnabled => - // Selecting `name` from a type `T | Null` is like selecting `name` from `T`, if - // unsafeNulls is enabled. This can throw at runtime, but we trade soundness for usability. - tp1.findMember(name, pre.stripNull, required, excluded) - case _ => + def goOr(tp: OrType) = + inline def searchAfterJoin = // we need to keep the invariant that `pre <: tp`. Branch `union-types-narrow-prefix` // achieved that by narrowing `pre` to each alternative, but it led to merge errors in // lots of places. The present strategy is instead of widen `tp` using `join` to be a // supertype of `pre`. go(tp.join) - } + + if Nullables.unsafeNullsEnabled then tp match + case OrNull(tp1) if tp1 <:< defn.ObjectType => + // Selecting `name` from a type `T | Null` is like selecting `name` from `T`, if + // unsafeNulls is enabled and T is a subtype of AnyRef. + // This can throw at runtime, but we trade soundness for usability. + tp1.findMember(name, pre.stripNull, required, excluded) + case _ => + searchAfterJoin + else searchAfterJoin val recCount = ctx.base.findMemberCount if (recCount >= Config.LogPendingFindMemberThreshold) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 433075f73fd9..ff8641f4b9c3 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -626,7 +626,7 @@ class Typer extends Namer val qual = typedExpr(tree.qualifier, shallowSelectionProto(tree.name, pt, this)) val qual1 = if Nullables.unsafeNullsEnabled then qual.tpe match { - case OrNull(tpe1) => + case OrNull(tpe1) if tpe1 <:< defn.ObjectType => qual.cast(AndType(qual.tpe, tpe1)) case tp => if tp.isNullType diff --git a/tests/explicit-nulls/pos/AnyValOrNull.scala b/tests/explicit-nulls/pos/AnyValOrNull.scala new file mode 100644 index 000000000000..ea3d419d8d77 --- /dev/null +++ b/tests/explicit-nulls/pos/AnyValOrNull.scala @@ -0,0 +1,16 @@ +def test1 = + val v: AnyVal | Null = null + if v == null then + println("null") + +def test2 = + val v: Int | Null = 1 + if v != null then + println(v) + +case class MyVal(val i: Boolean) extends AnyVal + +def test3 = + val v: MyVal | Null = MyVal(false) + if v != null then + println(v) From e36f4b000be04ff55f09564e17043e46e4693d01 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Wed, 27 Oct 2021 02:24:19 -0400 Subject: [PATCH 0775/1244] Add test for select --- .../src/dotty/tools/dotc/typer/TypeAssigner.scala | 2 +- tests/explicit-nulls/neg/AnyValOrNullSelect.scala | 13 +++++++++++++ tests/explicit-nulls/pos/AnyValOrNull.scala | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 tests/explicit-nulls/neg/AnyValOrNullSelect.scala diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index f7e33bd4a5f7..3dcec413540f 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -162,7 +162,7 @@ trait TypeAssigner { val qualType = qual.tpe.widenIfUnstable def kind = if tree.isType then "type" else "value" val foundWithoutNull = qualType match - case OrNull(qualType1) => + case OrNull(qualType1) if qualType1 <:< defn.ObjectType => val name = tree.name val pre = maybeSkolemizePrefix(qualType1, name) reallyExists(qualType1.findMember(name, pre)) diff --git a/tests/explicit-nulls/neg/AnyValOrNullSelect.scala b/tests/explicit-nulls/neg/AnyValOrNullSelect.scala new file mode 100644 index 000000000000..44e8b4e7edfb --- /dev/null +++ b/tests/explicit-nulls/neg/AnyValOrNullSelect.scala @@ -0,0 +1,13 @@ +case class MyVal(i: Int) extends AnyVal: + def printVal: Unit = + println(i) + +class Test: + val v: MyVal | Null = MyVal(1) + + def f1 = + v.printVal // error: value printVal is not a member of MyVal | Null + + def f1 = + import scala.language.unsafeNulls + v.printVal // error: value printVal is not a member of MyVal | Null diff --git a/tests/explicit-nulls/pos/AnyValOrNull.scala b/tests/explicit-nulls/pos/AnyValOrNull.scala index ea3d419d8d77..7fbe691901c3 100644 --- a/tests/explicit-nulls/pos/AnyValOrNull.scala +++ b/tests/explicit-nulls/pos/AnyValOrNull.scala @@ -8,7 +8,7 @@ def test2 = if v != null then println(v) -case class MyVal(val i: Boolean) extends AnyVal +case class MyVal(i: Boolean) extends AnyVal def test3 = val v: MyVal | Null = MyVal(false) From 91cee001fc08d0ae31bb3dc1ff31e318c5142a8e Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Wed, 27 Oct 2021 13:55:35 -0400 Subject: [PATCH 0776/1244] Update test --- tests/explicit-nulls/pos/AnyValOrNull.scala | 46 +++++++++++++++------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/tests/explicit-nulls/pos/AnyValOrNull.scala b/tests/explicit-nulls/pos/AnyValOrNull.scala index 7fbe691901c3..098d3eba973d 100644 --- a/tests/explicit-nulls/pos/AnyValOrNull.scala +++ b/tests/explicit-nulls/pos/AnyValOrNull.scala @@ -1,16 +1,36 @@ -def test1 = - val v: AnyVal | Null = null - if v == null then - println("null") +case class MyVal(i: Boolean) extends AnyVal -def test2 = - val v: Int | Null = 1 - if v != null then - println(v) +class Test1: -case class MyVal(i: Boolean) extends AnyVal + def test1 = + val v: AnyVal | Null = null + if v == null then + println("null") + + def test2 = + val v: Int | Null = 1 + if v != null then + println(v) + + def test3 = + val v: MyVal | Null = MyVal(false) + if v != null then + println(v) + +class Test2: + import scala.language.unsafeNulls + + def test1 = + val v: AnyVal | Null = null + if v == null then + println("null") + + def test2 = + val v: Int | Null = 1 + if v != null then + println(v) -def test3 = - val v: MyVal | Null = MyVal(false) - if v != null then - println(v) + def test3 = + val v: MyVal | Null = MyVal(false) + if v != null then + println(v) From 151c4d671f7cd458a2981b50827e535e3f34de13 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 22 Oct 2021 17:20:48 +0200 Subject: [PATCH 0777/1244] Add `scala.language.{3.1, 3.1-migration}` Fixes #13773 --- .../scala/runtime/stdLibPatches/language.scala | 18 +++++++++++++++++- project/MiMaFilters.scala | 8 ++++++++ tests/pos/source-import-3-0-migration.scala | 1 + tests/pos/source-import-3-0.scala | 1 + tests/pos/source-import-3-1-migration.scala | 1 + tests/pos/source-import-3-1.scala | 1 + 6 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 tests/pos/source-import-3-0-migration.scala create mode 100644 tests/pos/source-import-3-0.scala create mode 100644 tests/pos/source-import-3-1-migration.scala create mode 100644 tests/pos/source-import-3-1.scala diff --git a/library/src/scala/runtime/stdLibPatches/language.scala b/library/src/scala/runtime/stdLibPatches/language.scala index 4a70bede8e8a..7c8c116a106e 100644 --- a/library/src/scala/runtime/stdLibPatches/language.scala +++ b/library/src/scala/runtime/stdLibPatches/language.scala @@ -148,17 +148,33 @@ object language: @compileTimeOnly("`3.0` can only be used at compile time in import statements") object `3.0` -/* This can be added when we go to 3.1 /** Set source version to 3.1-migration. * * @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]] */ + @compileTimeOnly("`3.1-migration` can only be used at compile time in import statements") object `3.1-migration` /** Set source version to 3.1 * * @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]] */ + @compileTimeOnly("`3.1` can only be used at compile time in import statements") object `3.1` + +/* This can be added when we go to 3.2 + /** Set source version to 3.2-migration. + * + * @see [[https://scalacenter.github.io/scala-3-migration-guide/docs/scala-3-migration-mode]] + */ + @compileTimeOnly("`3.2-migration` can only be used at compile time in import statements") + object `3.2-migration` + + /** Set source version to 3.2 + * + * @see [[https://scalacenter.github.io/scala-3-migration-guide/docs/scala-3-migration-mode]] + */ + @compileTimeOnly("`3.2` can only be used at compile time in import statements") + object `3.2` */ end language diff --git a/project/MiMaFilters.scala b/project/MiMaFilters.scala index 4ef5e4d69c57..ae3673016db1 100644 --- a/project/MiMaFilters.scala +++ b/project/MiMaFilters.scala @@ -9,5 +9,13 @@ object MiMaFilters { ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.append"), ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#TypeReprMethods.substituteTypes"), ProblemFilters.exclude[DirectMissingMethodProblem]("scala.quoted.Quotes#reflectModule#TypeReprMethods.substituteTypes"), + + // Should have been added in 3.1.0 + // These are only allowed on imports and therefore should not be present in binaries emitted before + // this addition of these members and therefore should not cause any conflicts. + ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.stdLibPatches.language.3.1-migration"), + ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.stdLibPatches.language.3.1"), + ProblemFilters.exclude[MissingClassProblem]("scala.runtime.stdLibPatches.language$3$u002E1$"), + ProblemFilters.exclude[MissingClassProblem]("scala.runtime.stdLibPatches.language$3$u002E1$minusmigration$"), ) } diff --git a/tests/pos/source-import-3-0-migration.scala b/tests/pos/source-import-3-0-migration.scala new file mode 100644 index 000000000000..b0f220fd4e40 --- /dev/null +++ b/tests/pos/source-import-3-0-migration.scala @@ -0,0 +1 @@ +import language.`3.0-migration` diff --git a/tests/pos/source-import-3-0.scala b/tests/pos/source-import-3-0.scala new file mode 100644 index 000000000000..d6d7f9201b08 --- /dev/null +++ b/tests/pos/source-import-3-0.scala @@ -0,0 +1 @@ +import language.`3.0` diff --git a/tests/pos/source-import-3-1-migration.scala b/tests/pos/source-import-3-1-migration.scala new file mode 100644 index 000000000000..6e6f9f905b99 --- /dev/null +++ b/tests/pos/source-import-3-1-migration.scala @@ -0,0 +1 @@ +import language.`3.1-migration` diff --git a/tests/pos/source-import-3-1.scala b/tests/pos/source-import-3-1.scala new file mode 100644 index 000000000000..38216d612864 --- /dev/null +++ b/tests/pos/source-import-3-1.scala @@ -0,0 +1 @@ +import language.`3.1` From a41d3841ced737090c2638ba1f6b30e4121c97ab Mon Sep 17 00:00:00 2001 From: danicheg Date: Fri, 29 Oct 2021 12:33:04 +0300 Subject: [PATCH 0778/1244] Use https protocol in the link in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bd47a3ca013f..30789723d25a 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Dotty [![Dotty CI](https://github.com/lampepfl/dotty/workflows/Dotty/badge.svg?branch=master)](https://github.com/lampepfl/dotty/actions?query=branch%3Amaster) [![Join the chat at https://gitter.im/scala/scala](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/scala/scala?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -* [Homepage](http://dotty.epfl.ch) +* [Homepage](https://dotty.epfl.ch) * [Documentation](https://dotty.epfl.ch/docs) Try it out From 3b1066054dd0bc5d87724c38d2428400cf371767 Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Wed, 27 Oct 2021 19:48:05 -0700 Subject: [PATCH 0779/1244] Fix typos in `Tuple` docs --- library/src/scala/Tuple.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/src/scala/Tuple.scala b/library/src/scala/Tuple.scala index 06d258e3e503..c509551ef12e 100644 --- a/library/src/scala/Tuple.scala +++ b/library/src/scala/Tuple.scala @@ -8,16 +8,16 @@ import compiletime.ops.int._ sealed trait Tuple extends Product { import Tuple._ - /** Create a copy this tuple as an Array */ + /** Create a copy of this tuple as an Array */ inline def toArray: Array[Object] = runtime.Tuples.toArray(this) - /** Create a copy this tuple as a List */ + /** Create a copy of this tuple as a List */ inline def toList: List[Union[this.type]] = this.productIterator.toList .asInstanceOf[List[Union[this.type]]] - /** Create a copy this tuple as an IArray */ + /** Create a copy of this tuple as an IArray */ inline def toIArray: IArray[Object] = runtime.Tuples.toIArray(this) From a5cc262925819f51ef3f3fa9fe223b3a8e499aa0 Mon Sep 17 00:00:00 2001 From: Adrien Piquerez Date: Fri, 29 Oct 2021 10:51:02 +0200 Subject: [PATCH 0780/1244] Fix error summary printed twice Fix https://github.com/sbt/sbt/issues/6687 `printSummary` is already called in `Driver.finish`: https://github.com/lampepfl/dotty/blob/29f03741b9668c5052ec2b9502d061b7ecd614df/compiler/src/dotty/tools/dotc/Driver.scala#L53 --- sbt-bridge/src/dotty/tools/xsbt/CompilerBridgeDriver.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sbt-bridge/src/dotty/tools/xsbt/CompilerBridgeDriver.java b/sbt-bridge/src/dotty/tools/xsbt/CompilerBridgeDriver.java index 6c622063a141..12291120b157 100644 --- a/sbt-bridge/src/dotty/tools/xsbt/CompilerBridgeDriver.java +++ b/sbt-bridge/src/dotty/tools/xsbt/CompilerBridgeDriver.java @@ -91,10 +91,10 @@ public int compare(VirtualFile x0, VirtualFile x1) { callback.problem(problem.category(), problem.position(), problem.message(), problem.severity(), true); } + } else { + delegate.printSummary(); } - delegate.printSummary(); - if (delegate.hasErrors()) { log.debug(() -> "Compilation failed"); throw new InterfaceCompileFailed(args, delegate.problems(), "Compilation failed"); From a65057f4574f05ffadf9594e0443a47d6dc81b74 Mon Sep 17 00:00:00 2001 From: ghostbuster91 Date: Tue, 26 Oct 2021 19:34:14 +0200 Subject: [PATCH 0781/1244] Fix missing code-completion on standalone annotations Co-authored-by: Stefan Pavikevik Co-authored-by: Tomasz Godzik Co-authored-by: Anatolii Kmetiuk --- compiler/src/dotty/tools/dotc/parsing/Parsers.scala | 6 +++++- compiler/test/dotty/tools/repl/TabcompleteTests.scala | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index aff7218e662b..63b6e9f8ac51 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -3472,7 +3472,11 @@ object Parsers { givenDef(start, mods, atSpan(in.skipToken()) { Mod.Given() }) case _ => syntaxErrorOrIncomplete(ExpectedStartOfTopLevelDefinition()) - EmptyTree + mods.annotations match { + case head :: Nil => head + case Nil => EmptyTree + case all => Block(all, errorTermTree) + } } /** ClassDef ::= id ClassConstr TemplateOpt diff --git a/compiler/test/dotty/tools/repl/TabcompleteTests.scala b/compiler/test/dotty/tools/repl/TabcompleteTests.scala index 932ab7058899..df5a159277b7 100644 --- a/compiler/test/dotty/tools/repl/TabcompleteTests.scala +++ b/compiler/test/dotty/tools/repl/TabcompleteTests.scala @@ -138,4 +138,8 @@ class TabcompleteTests extends ReplTest { tabComplete("import quoted.* ; def fooImpl(using Quotes): Expr[Int] = { import quotes.reflect.* ; TypeRepr.of[Int].s")) } + @Test def i13624 = fromInitialState { implicit s => + assertEquals(List("implicitNotFound"), tabComplete("@annotation.implicitNot")) + assertEquals(List("main"), tabComplete("@annotation.implicitNotFound @mai")) + } } From a3fdd0a01617fac332648717067a84a9c68f9c2a Mon Sep 17 00:00:00 2001 From: ghostbuster91 Date: Mon, 1 Nov 2021 07:31:09 +0100 Subject: [PATCH 0782/1244] Move tests to CompletionTests file --- .../dotty/tools/repl/TabcompleteTests.scala | 5 ----- .../tools/languageserver/CompletionTest.scala | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/compiler/test/dotty/tools/repl/TabcompleteTests.scala b/compiler/test/dotty/tools/repl/TabcompleteTests.scala index df5a159277b7..dd5d5391a788 100644 --- a/compiler/test/dotty/tools/repl/TabcompleteTests.scala +++ b/compiler/test/dotty/tools/repl/TabcompleteTests.scala @@ -137,9 +137,4 @@ class TabcompleteTests extends ReplTest { assertEquals(List("select", "show", "simplified", "substituteTypes"), tabComplete("import quoted.* ; def fooImpl(using Quotes): Expr[Int] = { import quotes.reflect.* ; TypeRepr.of[Int].s")) } - - @Test def i13624 = fromInitialState { implicit s => - assertEquals(List("implicitNotFound"), tabComplete("@annotation.implicitNot")) - assertEquals(List("main"), tabComplete("@annotation.implicitNotFound @mai")) - } } diff --git a/language-server/test/dotty/tools/languageserver/CompletionTest.scala b/language-server/test/dotty/tools/languageserver/CompletionTest.scala index 1dd9516de7d1..6ef219187475 100644 --- a/language-server/test/dotty/tools/languageserver/CompletionTest.scala +++ b/language-server/test/dotty/tools/languageserver/CompletionTest.scala @@ -946,4 +946,21 @@ class CompletionTest { ("MyAnnotation", Module, "Foo.MyAnnotation") ) ) + + @Test def i13624_annotation : Unit = + code"""@annotation.implicitNot${m1} + |@annotation.implicitNotFound @mai${m2}""" + .withSource + .completion(m1, + Set( + ("implicitNotFound", Class, "scala.annotation.implicitNotFound"), + ("implicitNotFound", Module, "scala.annotation.implicitNotFound") + ) + ) + .completion(m2, + Set( + ("main", Class, "scala.main"), + ("main", Module, "main") + ) + ) } From 467ce40e227975d53e5c7c82522db82714d9ae96 Mon Sep 17 00:00:00 2001 From: ghostbuster91 Date: Mon, 1 Nov 2021 07:33:37 +0100 Subject: [PATCH 0783/1244] Add unnecessary deleted empty line --- compiler/test/dotty/tools/repl/TabcompleteTests.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/test/dotty/tools/repl/TabcompleteTests.scala b/compiler/test/dotty/tools/repl/TabcompleteTests.scala index dd5d5391a788..932ab7058899 100644 --- a/compiler/test/dotty/tools/repl/TabcompleteTests.scala +++ b/compiler/test/dotty/tools/repl/TabcompleteTests.scala @@ -137,4 +137,5 @@ class TabcompleteTests extends ReplTest { assertEquals(List("select", "show", "simplified", "substituteTypes"), tabComplete("import quoted.* ; def fooImpl(using Quotes): Expr[Int] = { import quotes.reflect.* ; TypeRepr.of[Int].s")) } + } From 43b4d1064689787a551a93e0f8d80a40daad8d74 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Tue, 26 Oct 2021 15:48:32 +0200 Subject: [PATCH 0784/1244] Add `-Xmacro-check` for Block constructors Checks that all definitions in the block have the same owner Closes #13809 --- .../quoted/runtime/impl/QuotesImpl.scala | 26 +- tests/neg-macros/i13809/Macros_1.scala | 265 ++++++++++++++++++ tests/neg-macros/i13809/Test_2.scala | 19 ++ tests/pos-macros/i10151/Macro_1.scala | 4 +- 4 files changed, 311 insertions(+), 3 deletions(-) create mode 100644 tests/neg-macros/i13809/Macros_1.scala create mode 100644 tests/neg-macros/i13809/Test_2.scala diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index 8a8e34901a3b..1510640cfce6 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -753,9 +753,9 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler object Block extends BlockModule: def apply(stats: List[Statement], expr: Term): Block = - withDefaultPos(tpd.Block(stats, expr)) + xCheckMacroBlockOwners(withDefaultPos(tpd.Block(stats, expr))) def copy(original: Tree)(stats: List[Statement], expr: Term): Block = - tpd.cpy.Block(original)(stats, expr) + xCheckMacroBlockOwners(tpd.cpy.Block(original)(stats, expr)) def unapply(x: Block): (List[Statement], Term) = (x.statements, x.expr) end Block @@ -2913,6 +2913,28 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler case _ => traverseChildren(t) }.traverse(tree) + /** Checks that all definitions in this block have the same owner. + * Nested definitions are ignored and assumed to be correct by construction. + */ + private def xCheckMacroBlockOwners(tree: Tree): tree.type = + if xCheckMacro then + val defs = new tpd.TreeAccumulator[List[Tree]] { + def apply(defs: List[Tree], tree: Tree)(using Context): List[Tree] = + tree match + case tree: tpd.DefTree => tree :: defs + case _ => foldOver(defs, tree) + }.apply(Nil, tree) + val defOwners = defs.groupBy(_.symbol.owner) + assert(defOwners.size <= 1, + s"""Block contains definition with different owners. + |Found definitions ${defOwners.size} distinct owners: ${defOwners.keys.mkString(", ")} + | + |Block: ${Printer.TreeCode.show(tree)} + | + |${defOwners.map((owner, trees) => s"Definitions owned by $owner: \n${trees.map(Printer.TreeCode.show).mkString("\n")}").mkString("\n\n")} + |""".stripMargin) + tree + private def xCheckMacroValidExprs(terms: List[Term]): terms.type = if xCheckMacro then terms.foreach(xCheckMacroValidExpr) terms diff --git a/tests/neg-macros/i13809/Macros_1.scala b/tests/neg-macros/i13809/Macros_1.scala new file mode 100644 index 000000000000..774a8bf195ba --- /dev/null +++ b/tests/neg-macros/i13809/Macros_1.scala @@ -0,0 +1,265 @@ +package x + +import scala.annotation._ +import scala.quoted._ + +trait CB[+T] + +object CBM: + def pure[T](t:T):CB[T] = ??? + def map[A,B](fa:CB[A])(f: A=>B):CB[B] = ??? + def flatMap[A,B](fa:CB[A])(f: A=>CB[B]):CB[B] = ??? + def spawn[A](op: =>CB[A]): CB[A] = ??? + + +@compileTimeOnly("await should be inside async block") +def await[T](f: CB[T]): T = ??? + + +trait CpsExpr[T:Type](prev: Seq[Expr[?]]): + + def fLast(using Quotes): Expr[CB[T]] + def prependExprs(exprs: Seq[Expr[?]]): CpsExpr[T] + def append[A:Type](chunk: CpsExpr[A])(using Quotes): CpsExpr[A] + def syncOrigin(using Quotes): Option[Expr[T]] + def map[A:Type](f: Expr[T => A])(using Quotes): CpsExpr[A] = + MappedCpsExpr[T,A](Seq(),this,f) + def flatMap[A:Type](f: Expr[T => CB[A]])(using Quotes): CpsExpr[A] = + FlatMappedCpsExpr[T,A](Seq(),this,f) + + def transformed(using Quotes): Expr[CB[T]] = + import quotes.reflect._ + Block(prev.toList.map(_.asTerm), fLast.asTerm).asExprOf[CB[T]] + + +case class GenericSyncCpsExpr[T:Type](prev: Seq[Expr[?]],last: Expr[T]) extends CpsExpr[T](prev): + + override def fLast(using Quotes): Expr[CB[T]] = + '{ CBM.pure(${last}:T) } + + override def prependExprs(exprs: Seq[Expr[?]]): CpsExpr[T] = + copy(prev = exprs ++: prev) + + override def syncOrigin(using Quotes): Option[Expr[T]] = + import quotes.reflect._ + Some(Block(prev.toList.map(_.asTerm), last.asTerm).asExprOf[T]) + + override def append[A:Type](e: CpsExpr[A])(using Quotes) = + e.prependExprs(Seq(last)).prependExprs(prev) + + override def map[A:Type](f: Expr[T => A])(using Quotes): CpsExpr[A] = + copy(last = '{ $f($last) }) + + override def flatMap[A:Type](f: Expr[T => CB[A]])(using Quotes): CpsExpr[A] = + GenericAsyncCpsExpr[A](prev, '{ CBM.flatMap(CBM.pure($last))($f) } ) + + +abstract class AsyncCpsExpr[T:Type]( + prev: Seq[Expr[?]] + ) extends CpsExpr[T](prev): + + override def append[A:Type](e: CpsExpr[A])(using Quotes): CpsExpr[A] = + flatMap( '{ (x:T) => ${e.transformed} }) + + override def syncOrigin(using Quotes): Option[Expr[T]] = None + + + +case class GenericAsyncCpsExpr[T:Type]( + prev: Seq[Expr[?]], + fLastExpr: Expr[CB[T]] + ) extends AsyncCpsExpr[T](prev): + + override def fLast(using Quotes): Expr[CB[T]] = fLastExpr + + override def prependExprs(exprs: Seq[Expr[?]]): CpsExpr[T] = + copy(prev = exprs ++: prev) + + override def map[A:Type](f: Expr[T => A])(using Quotes): CpsExpr[A] = + MappedCpsExpr(Seq(),this,f) + + override def flatMap[A:Type](f: Expr[T => CB[A]])(using Quotes): CpsExpr[A] = + FlatMappedCpsExpr(Seq(),this,f) + + + +case class MappedCpsExpr[S:Type, T:Type]( + prev: Seq[Expr[?]], + point: CpsExpr[S], + mapping: Expr[S=>T] + ) extends AsyncCpsExpr[T](prev): + + override def fLast(using Quotes): Expr[CB[T]] = + '{ CBM.map(${point.transformed})($mapping) } + + override def prependExprs(exprs: Seq[Expr[?]]): CpsExpr[T] = + copy(prev = exprs ++: prev) + + + +case class FlatMappedCpsExpr[S:Type, T:Type]( + prev: Seq[Expr[?]], + point: CpsExpr[S], + mapping: Expr[S => CB[T]] + ) extends AsyncCpsExpr[T](prev): + + override def fLast(using Quotes): Expr[CB[T]] = + '{ CBM.flatMap(${point.transformed})($mapping) } + + override def prependExprs(exprs: Seq[Expr[?]]): CpsExpr[T] = + copy(prev = exprs ++: prev) + + +class ValRhsFlatMappedCpsExpr[T:Type, V:Type](using thisQuotes: Quotes) + ( + prev: Seq[Expr[?]], + oldValDef: quotes.reflect.ValDef, + cpsRhs: CpsExpr[V], + next: CpsExpr[T] + ) + extends AsyncCpsExpr[T](prev) { + + override def fLast(using Quotes):Expr[CB[T]] = + import quotes.reflect._ + next.syncOrigin match + case Some(nextOrigin) => + // owner of this block is incorrect + '{ + CBM.map(${cpsRhs.transformed})((vx:V) => + ${buildAppendBlockExpr('vx, nextOrigin)}) + } + case None => + '{ + CBM.flatMap(${cpsRhs.transformed})((v:V)=> + ${buildAppendBlockExpr('v, next.transformed)}) + } + + + override def prependExprs(exprs: Seq[Expr[?]]): CpsExpr[T] = + ValRhsFlatMappedCpsExpr(using thisQuotes)(exprs ++: prev,oldValDef,cpsRhs,next) + + override def append[A:quoted.Type](e: CpsExpr[A])(using Quotes) = + ValRhsFlatMappedCpsExpr(using thisQuotes)(prev,oldValDef,cpsRhs,next.append(e)) + + + private def buildAppendBlock(using Quotes)(rhs:quotes.reflect.Term, + exprTerm:quotes.reflect.Term): quotes.reflect.Term = + import quotes.reflect._ + import scala.quoted.Expr + + val castedOldValDef = oldValDef.asInstanceOf[quotes.reflect.ValDef] + val valDef = ValDef(castedOldValDef.symbol, Some(rhs.changeOwner(castedOldValDef.symbol))) + exprTerm match + case Block(stats,last) => + Block(valDef::stats, last) + case other => + Block(valDef::Nil,other) + + private def buildAppendBlockExpr[A:Type](using Quotes)(rhs: Expr[V], expr:Expr[A]):Expr[A] = + import quotes.reflect._ + buildAppendBlock(rhs.asTerm,expr.asTerm).asExprOf[A] + +} + + +object CpsExpr: + + def sync[T:Type](f: Expr[T]): CpsExpr[T] = + GenericSyncCpsExpr[T](Seq(), f) + + def async[T:Type](f: Expr[CB[T]]): CpsExpr[T] = + GenericAsyncCpsExpr[T](Seq(), f) + + +object Async: + + transparent inline def transform[T](inline expr: T) = ${ + Async.transformImpl[T]('expr) + } + + def transformImpl[T:Type](f: Expr[T])(using Quotes): Expr[CB[T]] = + import quotes.reflect._ + // println(s"before transformed: ${f.show}") + val cpsExpr = rootTransform[T](f) + val r = '{ CBM.spawn(${cpsExpr.transformed}) } + // println(s"transformed value: ${r.show}") + r + + def rootTransform[T:Type](f: Expr[T])(using Quotes): CpsExpr[T] = { + import quotes.reflect._ + f match + case '{ while ($cond) { $repeat } } => + val cpsRepeat = rootTransform(repeat.asExprOf[Unit]) + CpsExpr.async('{ + def _whilefun():CB[Unit] = + if ($cond) { + ${cpsRepeat.flatMap('{(x:Unit) => _whilefun()}).transformed} + } else { + CBM.pure(()) + } + _whilefun() + }.asExprOf[CB[T]]) + case _ => + val fTree = f.asTerm + fTree match { + case fun@Apply(fun1@TypeApply(obj2,targs2), args1) => + if (obj2.symbol.name == "await") { + val awaitArg = args1.head + CpsExpr.async(awaitArg.asExprOf[CB[T]]) + } else { + ??? + } + case Assign(left,right) => + left match + case id@Ident(x) => + right.tpe.widen.asType match + case '[r] => + val cpsRight = rootTransform(right.asExprOf[r]) + CpsExpr.async( + cpsRight.map[T]( + '{ (x:r) => ${Assign(left,'x.asTerm).asExprOf[T] } + }).transformed ) + case _ => ??? + case Block(prevs,last) => + val rPrevs = prevs.map{ p => + p match + case v@ValDef(vName,vtt,optRhs) => + optRhs.get.tpe.widen.asType match + case '[l] => + val cpsRight = rootTransform(optRhs.get.asExprOf[l]) + ValRhsFlatMappedCpsExpr(using quotes)(Seq(), v, cpsRight, CpsExpr.sync('{})) + case t: Term => + // TODO: rootTransform + t.asExpr match + case '{ $p: tp } => + rootTransform(p) + case other => + printf(other.show) + throw RuntimeException(s"can't handle term in block: $other") + case other => + printf(other.show) + throw RuntimeException(s"unknown tree type in block: $other") + } + val rLast = rootTransform(last.asExprOf[T]) + val blockResult = rPrevs.foldRight(rLast)((e,s) => e.append(s)) + val retval = CpsExpr.async(blockResult.transformed) + retval + //BlockTransform(cpsCtx).run(prevs,last) + case id@Ident(name) => + CpsExpr.sync(id.asExprOf[T]) + case tid@Typed(Ident(name), tp) => + CpsExpr.sync(tid.asExprOf[T]) + case matchTerm@Match(scrutinee, caseDefs) => + val nCases = caseDefs.map{ old => + CaseDef.copy(old)(old.pattern, old.guard, rootTransform(old.rhs.asExprOf[T]).transformed.asTerm) + } + CpsExpr.async(Match(scrutinee, nCases).asExprOf[CB[T]]) + case inlinedTerm@ Inlined(call,List(),body) => + rootTransform(body.asExprOf[T]) + case constTerm@Literal(_)=> + CpsExpr.sync(constTerm.asExprOf[T]) + case _ => + throw RuntimeException(s"language construction is not supported: ${fTree}") + } + } + diff --git a/tests/neg-macros/i13809/Test_2.scala b/tests/neg-macros/i13809/Test_2.scala new file mode 100644 index 000000000000..3360de7ab018 --- /dev/null +++ b/tests/neg-macros/i13809/Test_2.scala @@ -0,0 +1,19 @@ +package x + +object VP1: + + ///* + def allocateServiceOperator(optInUsername: Option[String]): CB[Unit] = Async.transform { // error + val username = optInUsername match + case None => + while(false) { + val nextResult = await(op1()) + val countResult = await(op1()) + } + case Some(inUsername) => + val x = await(op1()) + inUsername + } + //*/ + + def op1(): CB[String] = ??? diff --git a/tests/pos-macros/i10151/Macro_1.scala b/tests/pos-macros/i10151/Macro_1.scala index c7a2b9a301c2..3b81ed00b2f8 100644 --- a/tests/pos-macros/i10151/Macro_1.scala +++ b/tests/pos-macros/i10151/Macro_1.scala @@ -55,7 +55,9 @@ object X: ) ) ) - case Block(stats, last) => Block(stats, transform(last)) + case Block(stats, last) => + val recoverdOwner = stats.headOption.map(_.symbol.owner).getOrElse(Symbol.spliceOwner) // hacky workaround to missing owner tracking in transform + Block(stats, transform(last).changeOwner(recoverdOwner)) case Inlined(x,List(),body) => transform(body) case l@Literal(x) => l.asExpr match From 2100c6933287cafde1248fdfbadbb57923c0903d Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 1 Nov 2021 14:17:09 +0100 Subject: [PATCH 0785/1244] Detect opaque aliases in inline val types `inline val`s cannot contain opaque aliases as these cannot be inlined through their type due to their opaqueness. We can support `inline def` with opaque types. Fixes #13851 Fixes #13852 --- .../src/dotty/tools/dotc/core/Types.scala | 29 ++++++++++++------- .../tools/dotc/transform/InlineVals.scala | 6 ++-- tests/neg/i13851.scala | 11 +++++++ tests/neg/i13851b.scala | 10 +++++++ tests/neg/i13852.scala | 6 ++++ 5 files changed, 49 insertions(+), 13 deletions(-) create mode 100644 tests/neg/i13851.scala create mode 100644 tests/neg/i13851b.scala create mode 100644 tests/neg/i13852.scala diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index ae7ec91e7108..b384cbdcb084 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1363,25 +1363,26 @@ object Types { case Atoms.Unknown => Atoms.Unknown case _ => Atoms.Unknown - private def dealias1(keep: AnnotatedType => Context ?=> Boolean)(using Context): Type = this match { + private def dealias1(keep: AnnotatedType => Context ?=> Boolean, keepOpaques: Boolean)(using Context): Type = this match { case tp: TypeRef => if (tp.symbol.isClass) tp else tp.info match { - case TypeAlias(alias) => alias.dealias1(keep) + case TypeAlias(alias) if !(keepOpaques && tp.symbol.is(Opaque)) => + alias.dealias1(keep, keepOpaques) case _ => tp } case app @ AppliedType(tycon, _) => - val tycon1 = tycon.dealias1(keep) - if (tycon1 ne tycon) app.superType.dealias1(keep) + val tycon1 = tycon.dealias1(keep, keepOpaques) + if (tycon1 ne tycon) app.superType.dealias1(keep, keepOpaques) else this case tp: TypeVar => val tp1 = tp.instanceOpt - if (tp1.exists) tp1.dealias1(keep) else tp + if (tp1.exists) tp1.dealias1(keep, keepOpaques) else tp case tp: AnnotatedType => - val tp1 = tp.parent.dealias1(keep) + val tp1 = tp.parent.dealias1(keep, keepOpaques) if keep(tp) then tp.derivedAnnotatedType(tp1, tp.annot) else tp1 case tp: LazyRef => - tp.ref.dealias1(keep) + tp.ref.dealias1(keep, keepOpaques) case _ => this } @@ -1389,16 +1390,22 @@ object Types { * TypeVars until type is no longer alias type, annotated type, LazyRef, * or instantiated type variable. */ - final def dealias(using Context): Type = dealias1(keepNever) + final def dealias(using Context): Type = dealias1(keepNever, keepOpaques = false) /** Follow aliases and dereferences LazyRefs and instantiated TypeVars until type * is no longer alias type, LazyRef, or instantiated type variable. * Goes through annotated types and rewraps annotations on the result. */ - final def dealiasKeepAnnots(using Context): Type = dealias1(keepAlways) + final def dealiasKeepAnnots(using Context): Type = dealias1(keepAlways, keepOpaques = false) /** Like `dealiasKeepAnnots`, but keeps only refining annotations */ - final def dealiasKeepRefiningAnnots(using Context): Type = dealias1(keepIfRefining) + final def dealiasKeepRefiningAnnots(using Context): Type = dealias1(keepIfRefining, keepOpaques = false) + + /** Follow non-opaque aliases and dereferences LazyRefs, annotated types and instantiated + * TypeVars until type is no longer alias type, annotated type, LazyRef, + * or instantiated type variable. + */ + final def dealiasKeepOpaques(using Context): Type = dealias1(keepNever, keepOpaques = true) /** Approximate this type with a type that does not contain skolem types. */ final def deskolemized(using Context): Type = @@ -1426,7 +1433,7 @@ object Types { def tryNormalize(using Context): Type = NoType private def widenDealias1(keep: AnnotatedType => Context ?=> Boolean)(using Context): Type = { - val res = this.widen.dealias1(keep) + val res = this.widen.dealias1(keep, keepOpaques = false) if (res eq this) res else res.widenDealias1(keep) } diff --git a/compiler/src/dotty/tools/dotc/transform/InlineVals.scala b/compiler/src/dotty/tools/dotc/transform/InlineVals.scala index 0e3f4139c27b..f3de86aab58a 100644 --- a/compiler/src/dotty/tools/dotc/transform/InlineVals.scala +++ b/compiler/src/dotty/tools/dotc/transform/InlineVals.scala @@ -33,13 +33,15 @@ class InlineVals extends MiniPhase: then val rhs = tree.rhs val tpt = tree.tpt - tpt.tpe.widenTermRefExpr.dealias.normalized match + tpt.tpe.widenTermRefExpr.dealiasKeepOpaques.normalized match case tp: ConstantType => if !isPureExpr(rhs) then val details = if enclosingInlineds.isEmpty then "" else em"but was: $rhs" report.error(s"inline value must be pure$details", rhs.srcPos) case tp => - if tp.derivesFrom(defn.UnitClass) then + if tp.typeSymbol.is(Opaque) then + report.error(em"`inline val` of type opaque types is not supported.\n\nTo inline consider using `inline def`", rhs) + else if tp.derivesFrom(defn.UnitClass) then report.error(em"`inline val` of type `Unit` is not supported.\n\nTo inline a `Unit` consider using `inline def`", rhs) else if tp.derivesFrom(defn.StringClass) || defn.ScalaValueClasses().exists(tp.derivesFrom(_)) then val pos = if tpt.span.isZeroExtent then rhs.srcPos else tpt.srcPos diff --git a/tests/neg/i13851.scala b/tests/neg/i13851.scala new file mode 100644 index 000000000000..fb7066a60b3f --- /dev/null +++ b/tests/neg/i13851.scala @@ -0,0 +1,11 @@ +opaque type One = 1 +inline val One: One = 1 // error + +opaque type Max = Int.MaxValue.type +inline val Max: Max = Int.MaxValue // error + +inline val MaxValue: Int.MaxValue.type = Int.MaxValue + +opaque type Two = 2 +type Bis = Two +inline val Two: Bis = 2 // error \ No newline at end of file diff --git a/tests/neg/i13851b.scala b/tests/neg/i13851b.scala new file mode 100644 index 000000000000..624735de0a49 --- /dev/null +++ b/tests/neg/i13851b.scala @@ -0,0 +1,10 @@ +object Num { + opaque type One = 1 + inline val One: One = 1 // error + + opaque type Two = 2 + inline def Two: Two = 2 +} + +def test1 = Num.One +def test2 = Num.Two diff --git a/tests/neg/i13852.scala b/tests/neg/i13852.scala new file mode 100644 index 000000000000..a0c5e726e1a8 --- /dev/null +++ b/tests/neg/i13852.scala @@ -0,0 +1,6 @@ +inline val `1`: 1 = 1 +def get1: 1 = `1` + +opaque type One = 1 +inline val One: One = 1 // error +def getOne: One = One From 40e99fef4a9671d750cc07acdfe37e604d611061 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Tue, 2 Nov 2021 10:31:37 +0100 Subject: [PATCH 0786/1244] Update compiler/src/dotty/tools/dotc/transform/InlineVals.scala Co-authored-by: Guillaume Martres --- compiler/src/dotty/tools/dotc/transform/InlineVals.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/transform/InlineVals.scala b/compiler/src/dotty/tools/dotc/transform/InlineVals.scala index f3de86aab58a..30ef0ed40375 100644 --- a/compiler/src/dotty/tools/dotc/transform/InlineVals.scala +++ b/compiler/src/dotty/tools/dotc/transform/InlineVals.scala @@ -40,7 +40,7 @@ class InlineVals extends MiniPhase: report.error(s"inline value must be pure$details", rhs.srcPos) case tp => if tp.typeSymbol.is(Opaque) then - report.error(em"`inline val` of type opaque types is not supported.\n\nTo inline consider using `inline def`", rhs) + report.error(em"The type of an `inline val` cannot be an opaque type.\n\nTo inline, consider using `inline def` instead", rhs) else if tp.derivesFrom(defn.UnitClass) then report.error(em"`inline val` of type `Unit` is not supported.\n\nTo inline a `Unit` consider using `inline def`", rhs) else if tp.derivesFrom(defn.StringClass) || defn.ScalaValueClasses().exists(tp.derivesFrom(_)) then From c340ed54776a460f1cf0150fc925095842ec288f Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 22 Oct 2021 17:07:34 +0200 Subject: [PATCH 0787/1244] Allow dual Scala 2/3 in non-experimental scopes --- .../dotc/transform/PruneErasedDefs.scala | 3 ++- .../no-experimental/i8945.scala | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 tests/pos-custom-args/no-experimental/i8945.scala diff --git a/compiler/src/dotty/tools/dotc/transform/PruneErasedDefs.scala b/compiler/src/dotty/tools/dotc/transform/PruneErasedDefs.scala index 12c6477262f8..7d8f0025eb15 100644 --- a/compiler/src/dotty/tools/dotc/transform/PruneErasedDefs.scala +++ b/compiler/src/dotty/tools/dotc/transform/PruneErasedDefs.scala @@ -55,7 +55,8 @@ class PruneErasedDefs extends MiniPhase with SymTransformer { thisTransform => tree def checkErasedInExperimental(sym: Symbol)(using Context): Unit = - if sym.is(Erased) && sym != defn.Compiletime_erasedValue && !sym.isInExperimentalScope then + // Make an exception for Scala 2 experimental macros to allow dual Scala 2/3 macros under non experimental mode + if sym.is(Erased, butNot = Macro) && sym != defn.Compiletime_erasedValue && !sym.isInExperimentalScope then Feature.checkExperimentalFeature("erased", sym.sourcePos) } diff --git a/tests/pos-custom-args/no-experimental/i8945.scala b/tests/pos-custom-args/no-experimental/i8945.scala new file mode 100644 index 000000000000..5dded16f0160 --- /dev/null +++ b/tests/pos-custom-args/no-experimental/i8945.scala @@ -0,0 +1,27 @@ +// src-2/MacroImpl.scala +trait Context { + object universe { + type Literal + } +} + +class MacroImpl(val c: Context) { + import c.universe.* + def mono: Literal = ??? +} + +// src-3/Macros.scala +import scala.language.experimental.macros + +object Macros { + + object Bundles { + def mono: Unit = macro MacroImpl.mono + inline def mono: Unit = ${ Macros3.monoImpl } + } + + object Macros3 { + def monoImpl(using quoted.Quotes) = '{()} + } + +} \ No newline at end of file From c2bb00bbb3ed1cab1603d7cef603854faad457e9 Mon Sep 17 00:00:00 2001 From: Seth Tisue Date: Mon, 25 Oct 2021 19:44:21 -0700 Subject: [PATCH 0788/1244] Lint trivially self-recursive extension methods Broadens Martin's fix for #13542 Fixes #9880 Also, exempt Boolean's && and || methods, which aren't set up as having by-name parameters. Co-authored-by: Dale Wijnand --- .../transform/CheckLoopingImplicits.scala | 9 ++++-- .../fatal-warnings/i9880.scala | 30 +++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 tests/neg-custom-args/fatal-warnings/i9880.scala diff --git a/compiler/src/dotty/tools/dotc/transform/CheckLoopingImplicits.scala b/compiler/src/dotty/tools/dotc/transform/CheckLoopingImplicits.scala index 4818153e00e6..21b994a6d1b8 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckLoopingImplicits.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckLoopingImplicits.scala @@ -46,7 +46,10 @@ class CheckLoopingImplicits extends MiniPhase: case Apply(fn, args) => checkNotLooping(fn) fn.tpe.widen match - case mt: MethodType => + case mt: MethodType + // Boolean && and || aren't defined with by-name parameters + // and therefore their type isn't an ExprType, so we exempt them by symbol name + if t.symbol != defn.Boolean_&& && t.symbol != defn.Boolean_|| => args.lazyZip(mt.paramInfos).foreach { (arg, pinfo) => if !pinfo.isInstanceOf[ExprType] then checkNotLooping(arg) } @@ -80,8 +83,8 @@ class CheckLoopingImplicits extends MiniPhase: checkNotLooping(t.rhs) case _ => - if sym.isOneOf(GivenOrImplicit | Lazy) then + if sym.isOneOf(GivenOrImplicit | Lazy | ExtensionMethod) then checkNotLooping(mdef.rhs) mdef end transform -end CheckLoopingImplicits \ No newline at end of file +end CheckLoopingImplicits diff --git a/tests/neg-custom-args/fatal-warnings/i9880.scala b/tests/neg-custom-args/fatal-warnings/i9880.scala new file mode 100644 index 000000000000..d9d857110543 --- /dev/null +++ b/tests/neg-custom-args/fatal-warnings/i9880.scala @@ -0,0 +1,30 @@ +opaque type Bytes = Array[Byte] +object Bytes: + extension (self: Bytes) + def size: Int = (self: Array[Byte]).size // error + +// + +object Module1: + opaque type State[S, +A] = S => (S, A) + object State: + extension [S, A](self: State[S, A]) + def map[B](f: A => B): State[S, B] = + s => { val (s2, a) = self(s); (s2, f(a)) } +object Module2: + import Module1.State + trait RNG + opaque type Gen[+A] = State[RNG, A] + object Gen: + extension [A](self: Gen[A]) + def map[B](f: A => B): Gen[B] = + self.map(f) // error + +// + +class Sym(val owner: Sym) + +extension (sym: Sym) + def isSomething: Boolean = false + def isFoo: Boolean = sym.isSomething && sym.owner.isFoo // was: Infinite loop in function body + def isBar: Boolean = sym.isSomething || sym.owner.isBar // was: Infinite loop in function body From d37098877d1f3202693aa7483ed333c14681a804 Mon Sep 17 00:00:00 2001 From: Stephane MICHELOUD Date: Thu, 21 Oct 2021 20:35:49 +0200 Subject: [PATCH 0789/1244] handle IOException for deleteIfExists --- .../dotc/classpath/MultiReleaseJarTest.scala | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compiler/test/dotty/tools/dotc/classpath/MultiReleaseJarTest.scala b/compiler/test/dotty/tools/dotc/classpath/MultiReleaseJarTest.scala index b79a34e1f2ab..79aeb87aed1d 100644 --- a/compiler/test/dotty/tools/dotc/classpath/MultiReleaseJarTest.scala +++ b/compiler/test/dotty/tools/dotc/classpath/MultiReleaseJarTest.scala @@ -2,18 +2,19 @@ package dotty.tools.dotc.classpath import dotty.tools.dotc.core.Contexts.Context -import java.io.ByteArrayOutputStream +import java.io.{ByteArrayOutputStream, IOException} import java.nio.file.{FileSystems, Files, Path} import java.util.jar.Attributes import java.util.jar.Attributes.Name -import org.junit.Test import org.junit.Assert._ +import org.junit.Test -import scala.util.Properties import scala.collection.JavaConverters._ +import scala.util.Properties class MultiReleaseJarTest extends dotty.tools.backend.jvm.DottyBytecodeTest { + @Test def mrJar(): Unit = { if (!Properties.isJavaAtLeast("9")) { println("skipping mrJar() on old JDK"); return } @@ -61,7 +62,10 @@ class MultiReleaseJarTest extends dotty.tools.backend.jvm.DottyBytecodeTest { if Properties.isJavaAtLeast("10") then assertEquals(Set("foo1", "foo2", "bar1", "bar2"), apiMethods(jar3, "10")) } finally - List(jar1, jar2, jar3).foreach(Files.deleteIfExists) + List(jar1, jar2, jar3).forall(path => + try Files.deleteIfExists(path) + catch case _: IOException => false + ) } @Test @@ -82,7 +86,6 @@ class MultiReleaseJarTest extends dotty.tools.backend.jvm.DottyBytecodeTest { assertTrue(classExists("java.lang.invoke.LambdaMetafactory", "9")) } - private def createManifest = { val manifest = new java.util.jar.Manifest() manifest.getMainAttributes.put(Name.MANIFEST_VERSION, "1.0") @@ -92,6 +95,7 @@ class MultiReleaseJarTest extends dotty.tools.backend.jvm.DottyBytecodeTest { val manifestBytes = os.toByteArray manifestBytes } + private def createZip(zipLocation: Path, content: List[(String, Array[Byte])]): Unit = { val env = new java.util.HashMap[String, String]() Files.deleteIfExists(zipLocation) @@ -113,4 +117,5 @@ class MultiReleaseJarTest extends dotty.tools.backend.jvm.DottyBytecodeTest { zipfs.close() } } + } From 3ee5fc1fb521d3339a4a7224c28a17fa7ffb9f62 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Wed, 13 Oct 2021 13:05:33 +0200 Subject: [PATCH 0790/1244] Remove unnecessary call to constrainResult This was originally added in #1395 to make the following compile: (1, x => 2): (Int, Int => Int) But reverting this change doesn't break anything anymore: the other call to `constrainResult` in `Application#init` is enough to propagate the constraint needed to type lambda. The strange thing is that this call already existed before #1395, I don't know why it wasn't enough back then. --- compiler/src/dotty/tools/dotc/typer/Applications.scala | 9 --------- 1 file changed, 9 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index ab7187f6f4d4..ae4bc2f395d0 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -891,15 +891,6 @@ trait Applications extends Compatibility { then originalProto.tupledDual else originalProto - // If some of the application's arguments are function literals without explicitly declared - // parameter types, relate the normalized result type of the application with the - // expected type through `constrainResult`. This can add more constraints which - // help sharpen the inferred parameter types for the argument function literal(s). - // This tweak is needed to make i1378 compile. - if (tree.args.exists(untpd.isFunctionWithUnknownParamType(_))) - if (!constrainResult(tree.symbol, fun1.tpe.widen, proto.derivedFunProto(resultType = pt))) - typr.println(i"result failure for $tree with type ${fun1.tpe.widen}, expected = $pt") - /** Type application where arguments come from prototype, and no implicits are inserted */ def simpleApply(fun1: Tree, proto: FunProto)(using Context): Tree = methPart(fun1).tpe match { From 85eafec05e7a499333b5004624c7b3cbefeebaed Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Fri, 15 Oct 2021 12:01:25 +0200 Subject: [PATCH 0791/1244] Fix improper usage of `constrained` breaking type inference In multiple places, we had code equivalent to the following pattern: val (tl2, targs) = constrained(tl) tl2.resultType <:< ... which lead to subtype checks directly involving the TypeParamRefs of the constrained type lambda. This commit uses the following pattern instead: val (tl2, targs) = constrained(tl) tl2.instantiate(targs.map(_.tpe)) <:< ... which substitutes the TypeParamRefs by the corresponding TypeVars in the constraint. This is necessary because when comparing TypeParamRefs in isSubType: - we only recurse on the bounds of the TypeParamRef using `isSubTypeWhenFrozen` which prevents further constraints from being added (see the added stm.scala test case for an example where this matters). - if the corresponding TypeVar is instantiated and the TyperState has been gc()'ed, there is no way to find the instantiation corresponding to the current TypeParamRef anymore. There is one place where I left the old logic intact: `TrackingTypeComparer#matchCase` because the match type caching logic (in `MatchType#reduced`) conflicted with the use of TypeVars since it retracts the current TyperState. This change breaks a test which involves an unlikely combination of implicit conversion, overloading and apply insertion. Given that there is always a tension between type inference and implicit conversion, and that we're discouraging uses of implicit conversions, I think that's an acceptable trade-off. --- compiler/src/dotty/tools/dotc/typer/Applications.scala | 6 +++--- compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala | 9 +++++++-- .../test/dotty/tools/dotc/core/ConstraintsTest.scala | 9 +++++---- tests/pos/stm.scala | 10 ++++++++++ tests/pos/t0851.scala | 3 +-- tests/pos/t2913.scala | 3 +-- 6 files changed, 27 insertions(+), 13 deletions(-) create mode 100644 tests/pos/stm.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index ae4bc2f395d0..1c346ac7af20 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -411,7 +411,7 @@ trait Applications extends Compatibility { */ @threadUnsafe lazy val methType: Type = liftedFunType.widen match { case funType: MethodType => funType - case funType: PolyType => constrained(funType).resultType + case funType: PolyType => instantiateWithTypeVars(funType) case tp => tp //was: funType } @@ -1562,7 +1562,7 @@ trait Applications extends Compatibility { case tp2: MethodType => true // (3a) case tp2: PolyType if tp2.resultType.isInstanceOf[MethodType] => true // (3a) case tp2: PolyType => // (3b) - explore(isAsSpecificValueType(tp1, constrained(tp2).resultType)) + explore(isAsSpecificValueType(tp1, instantiateWithTypeVars(tp2))) case _ => // 3b) isAsSpecificValueType(tp1, tp2) } @@ -1729,7 +1729,7 @@ trait Applications extends Compatibility { resultType.revealIgnored match { case resultType: ValueType => altType.widen match { - case tp: PolyType => resultConforms(altSym, constrained(tp).resultType, resultType) + case tp: PolyType => resultConforms(altSym, instantiateWithTypeVars(tp), resultType) case tp: MethodType => constrainResult(altSym, tp.resultType, resultType) case _ => true } diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index 167128be08e4..fcedd8a0cd56 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -659,6 +659,11 @@ object ProtoTypes { def constrained(tl: TypeLambda)(using Context): TypeLambda = constrained(tl, EmptyTree)._1 + /** Instantiate `tl` with fresh type variables added to the constraint. */ + def instantiateWithTypeVars(tl: TypeLambda)(using Context): Type = + val targs = constrained(tl, ast.tpd.EmptyTree, alwaysAddTypeVars = true)._2 + tl.instantiate(targs.tpes) + /** A new type variable with given bounds for its origin. * @param represents If exists, the TermParamRef that the TypeVar represents * in the substitution generated by `resultTypeApprox` @@ -707,7 +712,7 @@ object ProtoTypes { else mt.resultType /** The normalized form of a type - * - unwraps polymorphic types, tracking their parameters in the current constraint + * - instantiate polymorphic types with fresh type variables in the current constraint * - skips implicit parameters of methods and functions; * if result type depends on implicit parameter, replace with wildcard. * - converts non-dependent method types to the corresponding function types @@ -726,7 +731,7 @@ object ProtoTypes { Stats.record("normalize") tp.widenSingleton match { case poly: PolyType => - normalize(constrained(poly).resultType, pt) + normalize(instantiateWithTypeVars(poly), pt) case mt: MethodType => if (mt.isImplicitMethod) normalize(resultTypeApprox(mt, wildcardOnly = true), pt) else if (mt.isResultDependent) tp diff --git a/compiler/test/dotty/tools/dotc/core/ConstraintsTest.scala b/compiler/test/dotty/tools/dotc/core/ConstraintsTest.scala index 37ccf5667a7d..5ab162b9f05c 100644 --- a/compiler/test/dotty/tools/dotc/core/ConstraintsTest.scala +++ b/compiler/test/dotty/tools/dotc/core/ConstraintsTest.scala @@ -7,6 +7,7 @@ import dotty.tools.dotc.core.Contexts.{*, given} import dotty.tools.dotc.core.Decorators.{*, given} import dotty.tools.dotc.core.Symbols.* import dotty.tools.dotc.core.Types.* +import dotty.tools.dotc.ast.tpd.* import dotty.tools.dotc.typer.ProtoTypes.constrained import org.junit.Test @@ -18,8 +19,8 @@ class ConstraintsTest: @Test def mergeParamsTransitivity: Unit = inCompilerContext(TestConfiguration.basicClasspath, scalaSources = "trait A { def foo[S, T, R]: Any }") { - val tp = constrained(requiredClass("A").typeRef.select("foo".toTermName).info.asInstanceOf[TypeLambda]) - val List(s, t, r) = tp.paramRefs + val tvars = constrained(requiredClass("A").typeRef.select("foo".toTermName).info.asInstanceOf[TypeLambda], EmptyTree, alwaysAddTypeVars = true)._2 + val List(s, t, r) = tvars.tpes val innerCtx = ctx.fresh.setExploreTyperState() inContext(innerCtx) { @@ -37,8 +38,8 @@ class ConstraintsTest: @Test def mergeBoundsTransitivity: Unit = inCompilerContext(TestConfiguration.basicClasspath, scalaSources = "trait A { def foo[S, T]: Any }") { - val tp = constrained(requiredClass("A").typeRef.select("foo".toTermName).info.asInstanceOf[TypeLambda]) - val List(s, t) = tp.paramRefs + val tvars = constrained(requiredClass("A").typeRef.select("foo".toTermName).info.asInstanceOf[TypeLambda], EmptyTree, alwaysAddTypeVars = true)._2 + val List(s, t) = tvars.tpes val innerCtx = ctx.fresh.setExploreTyperState() inContext(innerCtx) { diff --git a/tests/pos/stm.scala b/tests/pos/stm.scala new file mode 100644 index 000000000000..48ff946f9b5c --- /dev/null +++ b/tests/pos/stm.scala @@ -0,0 +1,10 @@ +class Inv[X] +class Ref[X] +object Ref { + def apply(i: Inv[Int], x: Int): Ref[Int] = ??? + def apply[Y](i: Inv[Y], x: Y): Ref[Y] = ??? +} + +class A { + val ref: Ref[List[AnyRef]] = Ref(new Inv[List[AnyRef]], List.empty) +} diff --git a/tests/pos/t0851.scala b/tests/pos/t0851.scala index fdc504af75c5..c7393723b148 100644 --- a/tests/pos/t0851.scala +++ b/tests/pos/t0851.scala @@ -1,9 +1,8 @@ package test object test1 { - case class Foo[T,T2](f : (T,T2) => String) extends (((T,T2)) => String){ + case class Foo[T,T2](f : (T,T2) => String) { def apply(t : T) = (s:T2) => f(t,s) - def apply(p : (T,T2)) = f(p._1,p._2) } implicit def g[T](f : (T,String) => String): Foo[T, String] = Foo(f) def main(args : Array[String]) : Unit = { diff --git a/tests/pos/t2913.scala b/tests/pos/t2913.scala index f91ed7b51318..9d7b898cbe9d 100644 --- a/tests/pos/t2913.scala +++ b/tests/pos/t2913.scala @@ -33,9 +33,8 @@ object TestNoAutoTupling { // t0851 is essentially the same: object test1 { - case class Foo[T,T2](f : (T,T2) => String) extends (((T,T2)) => String){ + case class Foo[T,T2](f : (T,T2) => String) { def apply(t : T) = (s:T2) => f(t,s) - def apply(p : (T,T2)) = f(p._1,p._2) } implicit def g[T](f : (T,String) => String): test1.Foo[T,String] = Foo(f) def main(args : Array[String]) : Unit = { From 478622df724f71ec768c36b2c8d725053d0e0bf7 Mon Sep 17 00:00:00 2001 From: Seth Tisue Date: Thu, 21 Oct 2021 11:20:57 -0700 Subject: [PATCH 0792/1244] Warn on lossy conversion of literals & constants Co-authored-by: Dale Wijnand --- .../tools/dotc/reporting/ErrorMessageID.scala | 3 +- .../dotty/tools/dotc/reporting/messages.scala | 7 +++++ .../src/dotty/tools/dotc/typer/Typer.scala | 12 +++++++- .../fatal-warnings/i11333.check | 30 +++++++++++++++++++ .../fatal-warnings/i11333.scala | 12 ++++++++ 5 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 tests/neg-custom-args/fatal-warnings/i11333.check create mode 100644 tests/neg-custom-args/fatal-warnings/i11333.scala diff --git a/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala index d1b95d31dd62..342e640ca819 100644 --- a/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala +++ b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala @@ -174,7 +174,8 @@ enum ErrorMessageID extends java.lang.Enum[ErrorMessageID]: OverrideTypeMismatchErrorID, OverrideErrorID, MatchableWarningID, - CannotExtendFunctionID + CannotExtendFunctionID, + LossyWideningConstantConversionID def errorNumber = ordinal - 2 diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index 063ba96410c8..43f7f6f5ddb3 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -807,6 +807,13 @@ import transform.SymUtils._ |""" } + class LossyWideningConstantConversion(sourceType: Type, targetType: Type)(using Context) + extends Message(LossyWideningConstantConversionID): + def kind = "Lossy Conversion" + def msg = em"""|Widening conversion from $sourceType to $targetType loses precision. + |Write `.to$targetType` instead.""".stripMargin + def explain = "" + class PatternMatchExhaustivity(uncoveredFn: => String, hasMore: Boolean)(using Context) extends Message(PatternMatchExhaustivityID) { def kind = "Pattern Match Exhaustivity" diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index ff8641f4b9c3..1d87e03a638a 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -719,7 +719,11 @@ class Typer extends Namer else if (target.isRef(defn.FloatClass)) tree.kind match { case Whole(16) => // cant parse hex literal as float - case _ => return lit(floatFromDigits(digits)) + case _ => + val float = floatFromDigits(digits) + if digits.toIntOption.exists(_ != float.toInt) then + report.warning(LossyWideningConstantConversion(defn.IntType, target), tree.srcPos) + return lit(float) } else if (target.isRef(defn.DoubleClass)) tree.kind match { @@ -3733,6 +3737,12 @@ class Typer extends Namer case ConstantType(x) => val converted = x.convertTo(pt) if converted != null && (converted ne x) then + val cls = pt.classSymbol + if x.tag == IntTag && cls == defn.FloatClass && x.intValue.toFloat.toInt != x.intValue + || x.tag == LongTag && cls == defn.FloatClass && x.longValue.toFloat.toLong != x.longValue + || x.tag == LongTag && cls == defn.DoubleClass && x.longValue.toDouble.toLong != x.longValue + then + report.warning(LossyWideningConstantConversion(x.tpe, pt), tree.srcPos) return adaptConstant(tree, ConstantType(converted)) case _ => diff --git a/tests/neg-custom-args/fatal-warnings/i11333.check b/tests/neg-custom-args/fatal-warnings/i11333.check new file mode 100644 index 000000000000..beef37c6460a --- /dev/null +++ b/tests/neg-custom-args/fatal-warnings/i11333.check @@ -0,0 +1,30 @@ +-- [E167] Lossy Conversion Error: tests/neg-custom-args/fatal-warnings/i11333.scala:2:19 ------------------------------- +2 | val f1: Float = 123456789 // error + | ^^^^^^^^^ + | Widening conversion from Int to Float loses precision. + | Write `.toFloat` instead. +-- [E167] Lossy Conversion Error: tests/neg-custom-args/fatal-warnings/i11333.scala:3:19 ------------------------------- +3 | val d1: Double = 1234567890123456789L // error + | ^^^^^^^^^^^^^^^^^^^^ + | Widening conversion from Long to Double loses precision. + | Write `.toDouble` instead. +-- [E167] Lossy Conversion Error: tests/neg-custom-args/fatal-warnings/i11333.scala:4:19 ------------------------------- +4 | val f2: Float = 123456789L // error + | ^^^^^^^^^^ + | Widening conversion from Long to Float loses precision. + | Write `.toFloat` instead. +-- [E167] Lossy Conversion Error: tests/neg-custom-args/fatal-warnings/i11333.scala:10:21 ------------------------------ +10 | val f1_b: Float = i1 // error + | ^^ + | Widening conversion from Int to Float loses precision. + | Write `.toFloat` instead. +-- [E167] Lossy Conversion Error: tests/neg-custom-args/fatal-warnings/i11333.scala:11:21 ------------------------------ +11 | val d1_b: Double = l1 // error + | ^^ + | Widening conversion from Long to Double loses precision. + | Write `.toDouble` instead. +-- [E167] Lossy Conversion Error: tests/neg-custom-args/fatal-warnings/i11333.scala:12:21 ------------------------------ +12 | val f2_b: Float = l2 // error + | ^^ + | Widening conversion from Long to Float loses precision. + | Write `.toFloat` instead. diff --git a/tests/neg-custom-args/fatal-warnings/i11333.scala b/tests/neg-custom-args/fatal-warnings/i11333.scala new file mode 100644 index 000000000000..3ba39efeb29e --- /dev/null +++ b/tests/neg-custom-args/fatal-warnings/i11333.scala @@ -0,0 +1,12 @@ +class C: + val f1: Float = 123456789 // error + val d1: Double = 1234567890123456789L // error + val f2: Float = 123456789L // error + + inline val i1 = 123456789 + inline val l1 = 1234567890123456789L + inline val l2 = 123456789L + + val f1_b: Float = i1 // error + val d1_b: Double = l1 // error + val f2_b: Float = l2 // error From a3e768d6e99e30eae7148d6f597a34881e1517e2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 4 Nov 2021 10:58:36 +0100 Subject: [PATCH 0793/1244] Indicate name of classfile where leaky mapping of existential type happens Fixes #13873 --- .../tools/dotc/core/unpickleScala2/Scala2Unpickler.scala | 2 +- compiler/src/dotty/tools/dotc/reporting/messages.scala | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index a04a17bb3689..18f3e0b19d87 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -739,7 +739,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas val anyTypes = boundSyms map (_ => defn.AnyType) val boundBounds = boundSyms map (_.info.bounds.hi) val tp2 = tp1.subst(boundSyms, boundBounds).subst(boundSyms, anyTypes) - report.warning(FailureToEliminateExistential(tp, tp1, tp2, boundSyms)) + report.warning(FailureToEliminateExistential(tp, tp1, tp2, boundSyms, classRoot.symbol)) tp2 } else tp1 diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index 43f7f6f5ddb3..62bf295fed8c 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -1772,13 +1772,13 @@ import transform.SymUtils._ def explain = "" } - class FailureToEliminateExistential(tp: Type, tp1: Type, tp2: Type, boundSyms: List[Symbol])(using Context) + class FailureToEliminateExistential(tp: Type, tp1: Type, tp2: Type, boundSyms: List[Symbol], classRoot: Symbol)(using Context) extends Message(FailureToEliminateExistentialID) { def kind: String = "Compatibility" def msg = val originalType = ctx.printer.dclsText(boundSyms, "; ").show - em"""An existential type that came from a Scala-2 classfile cannot be - |mapped accurately to to a Scala-3 equivalent. + em"""An existential type that came from a Scala-2 classfile for $classRoot + |cannot be mapped accurately to a Scala-3 equivalent. |original type : $tp forSome ${originalType} |reduces to : $tp1 |type used instead: $tp2 From 2088c9c17325cc535fb2cfdf9e40f9c640fa1682 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Fri, 5 Nov 2021 02:09:38 -0400 Subject: [PATCH 0794/1244] Change Untyped from Null to Nothing --- compiler/src/dotty/tools/dotc/ast/Trees.scala | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 5bdd18705051..7aa4491c31de 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -19,13 +19,7 @@ import Decorators._ object Trees { - // Note: it would be more logical to make Untyped = Nothing. - // However, this interacts in a bad way with Scala's current type inference. - // In fact, we cannot write something like Select(pre, name), where pre is - // of type Tree[Nothing]; type inference will treat the Nothing as an uninstantiated - // value and will not infer Nothing as the type parameter for Select. - // We should come back to this issue once type inference is changed. - type Untyped = Null + type Untyped = Nothing /** The total number of created tree nodes, maintained if Stats.enabled */ @sharable var ntrees: Int = 0 @@ -44,8 +38,7 @@ object Trees { * * - You can never observe a `tpe` which is `null` (throws an exception) * - So when creating a typed tree with `withType` we can re-use - * the existing tree transparently, assigning its `tpe` field, - * provided it was `null` before. + * the existing tree transparently, assigning its `tpe` field. * - It is impossible to embed untyped trees in typed ones. * - Typed trees can be embedded in untyped ones provided they are rooted * in a TypedSplice node. From 0eb1d5eaec73c58aac74a513a857efe33796c7b6 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 4 Nov 2021 13:11:17 +0100 Subject: [PATCH 0795/1244] Refine treatment of TypeBounds in patterns Only map type bounds to pattern-bound symbols at the toplevel of a pattern, or when they appear as type arguments. Do not map them in refinements. Fixes #13820 --- .../src/dotty/tools/dotc/typer/Typer.scala | 54 ++++++++++--------- .../fatal-warnings/i13820.scala | 5 ++ tests/pos/i13820.scala | 5 ++ 3 files changed, 38 insertions(+), 26 deletions(-) create mode 100644 tests/neg-custom-args/fatal-warnings/i13820.scala create mode 100644 tests/pos/i13820.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 1d87e03a638a..f3cfed40f6c1 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -876,7 +876,7 @@ class Typer extends Namer wildName = nme.WILDCARD_STAR) } else { - def typedTpt = checkSimpleKinded(typedType(tree.tpt)) + def typedTpt = checkSimpleKinded(typedType(tree.tpt, mapPatternBounds = true)) def handlePattern: Tree = { val tpt1 = typedTpt if !ctx.isAfterTyper && pt != defn.ImplicitScrutineeTypeRef then @@ -1683,7 +1683,9 @@ class Typer extends Namer /** Type a case of a type match */ def typedTypeCase(cdef: untpd.CaseDef, selType: Type, pt: Type)(using Context): CaseDef = { def caseRest(using Context) = { - val pat1 = withMode(Mode.Pattern)(checkSimpleKinded(typedType(cdef.pat))) + val pat1 = withMode(Mode.Pattern) { + checkSimpleKinded(typedType(cdef.pat, mapPatternBounds = true)) + } val pat2 = indexPattern(cdef).transform(pat1) var body1 = typedType(cdef.body, pt) if !body1.isType then @@ -1924,7 +1926,7 @@ class Typer extends Namer // wildcard identifiers `_` instead. TypeTree(tparamBounds).withSpan(arg.span) case _ => - typed(desugaredArg, argPt) + typedType(desugaredArg, argPt, mapPatternBounds = true) } else desugaredArg.withType(UnspecifiedErrorType) } @@ -1991,36 +1993,18 @@ class Typer extends Namer assignType(cpy.ByNameTypeTree(tree)(result1), result1) } - def typedTypeBoundsTree(tree: untpd.TypeBoundsTree, pt: Type)(using Context): Tree = { + def typedTypeBoundsTree(tree: untpd.TypeBoundsTree, pt: Type)(using Context): Tree = val TypeBoundsTree(lo, hi, alias) = tree val lo1 = typed(lo) val hi1 = typed(hi) val alias1 = typed(alias) - val lo2 = if (lo1.isEmpty) typed(untpd.TypeTree(defn.NothingType)) else lo1 val hi2 = if (hi1.isEmpty) typed(untpd.TypeTree(defn.AnyType)) else hi1 - if !alias1.isEmpty then val bounds = TypeBounds(lo2.tpe, hi2.tpe) if !bounds.contains(alias1.tpe) then report.error(em"type ${alias1.tpe} outside bounds $bounds", tree.srcPos) - - val tree1 = assignType(cpy.TypeBoundsTree(tree)(lo2, hi2, alias1), lo2, hi2, alias1) - if (ctx.mode.is(Mode.Pattern)) - // Associate a pattern-bound type symbol with the wildcard. - // The bounds of the type symbol can be constrained when comparing a pattern type - // with an expected type in typedTyped. The type symbol and the defining Bind node - // are eliminated once the enclosing pattern has been typechecked; see `indexPattern` - // in `typedCase`. - //val ptt = if (lo.isEmpty && hi.isEmpty) pt else - if (ctx.isAfterTyper) tree1 - else { - val boundName = WildcardParamName.fresh().toTypeName - val wildcardSym = newPatternBoundSymbol(boundName, tree1.tpe & pt, tree.span) - untpd.Bind(boundName, tree1).withType(wildcardSym.typeRef) - } - else tree1 - } + assignType(cpy.TypeBoundsTree(tree)(lo2, hi2, alias1), lo2, hi2, alias1) def typedBind(tree: untpd.Bind, pt: Type)(using Context): Tree = { if !isFullyDefined(pt, ForceDegree.all) then @@ -2698,7 +2682,9 @@ class Typer extends Namer val pts = if (arity == pt.tupleArity) pt.tupleElementTypes else List.fill(arity)(defn.AnyType) - val elems = tree.trees.lazyZip(pts).map(typed(_, _)) + val elems = tree.trees.lazyZip(pts).map( + if ctx.mode.is(Mode.Type) then typedType(_, _, mapPatternBounds = true) + else typed(_, _)) if (ctx.mode.is(Mode.Type)) elems.foldRight(TypeTree(defn.EmptyTupleModule.termRef): Tree)((elemTpt, elemTpts) => AppliedTypeTree(TypeTree(defn.PairClass.typeRef), List(elemTpt, elemTpts))) @@ -3029,8 +3015,24 @@ class Typer extends Namer def typedExpr(tree: untpd.Tree, pt: Type = WildcardType)(using Context): Tree = withoutMode(Mode.PatternOrTypeBits)(typed(tree, pt)) - def typedType(tree: untpd.Tree, pt: Type = WildcardType)(using Context): Tree = // todo: retract mode between Type and Pattern? - withMode(Mode.Type) { typed(tree, pt) } + + def typedType(tree: untpd.Tree, pt: Type = WildcardType, mapPatternBounds: Boolean = false)(using Context): Tree = + val tree1 = withMode(Mode.Type) { typed(tree, pt) } + if mapPatternBounds && ctx.mode.is(Mode.Pattern) && !ctx.isAfterTyper then + tree1 match + case tree1: TypeBoundsTree => + // Associate a pattern-bound type symbol with the wildcard. + // The bounds of the type symbol can be constrained when comparing a pattern type + // with an expected type in typedTyped. The type symbol and the defining Bind node + // are eliminated once the enclosing pattern has been typechecked; see `indexPattern` + // in `typedCase`. + val boundName = WildcardParamName.fresh().toTypeName + val wildcardSym = newPatternBoundSymbol(boundName, tree1.tpe & pt, tree.span) + untpd.Bind(boundName, tree1).withType(wildcardSym.typeRef) + case tree1 => + tree1 + else tree1 + def typedPattern(tree: untpd.Tree, selType: Type = WildcardType)(using Context): Tree = withMode(Mode.Pattern)(typed(tree, selType)) diff --git a/tests/neg-custom-args/fatal-warnings/i13820.scala b/tests/neg-custom-args/fatal-warnings/i13820.scala new file mode 100644 index 000000000000..234c1a55450e --- /dev/null +++ b/tests/neg-custom-args/fatal-warnings/i13820.scala @@ -0,0 +1,5 @@ +trait Expr { type T } + +def foo[A](e: Expr { type T = A }) = e match + case e1: Expr { type T <: Int } => // error: type test cannot be checked at runtime + val i: Int = ??? : e1.T \ No newline at end of file diff --git a/tests/pos/i13820.scala b/tests/pos/i13820.scala new file mode 100644 index 000000000000..1accdee53fb1 --- /dev/null +++ b/tests/pos/i13820.scala @@ -0,0 +1,5 @@ +trait Expr { type T } + +def foo[A](e: Expr { type T = A }) = e match + case e1: Expr { type T <: Int } => + val i: Int = ??? : e1.T \ No newline at end of file From 07e1a8ede01a358497d40749cc6329e8389de701 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 6 Nov 2021 11:51:26 +0100 Subject: [PATCH 0796/1244] Fix crasher for missing integer argument on command line Fixes #13893 --- .../dotty/tools/dotc/config/Settings.scala | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/config/Settings.scala b/compiler/src/dotty/tools/dotc/config/Settings.scala index 1922007adc11..29a52defa4c6 100644 --- a/compiler/src/dotty/tools/dotc/config/Settings.scala +++ b/compiler/src/dotty/tools/dotc/config/Settings.scala @@ -98,16 +98,33 @@ object Settings: changed = true ArgsSummary(updateIn(sstate, value1), args, errors, dangers) end update + def fail(msg: String, args: List[String]) = ArgsSummary(sstate, args, errors :+ msg, warnings) + def missingArg = fail(s"missing argument for option $name", args) + def setString(argValue: String, args: List[String]) = choices match case Some(xs) if !xs.contains(argValue) => fail(s"$argValue is not a valid choice for $name", args) case _ => update(argValue, args) + + def setInt(argValue: String, args: List[String]) = + try + val x = argValue.toInt + choices match + case Some(r: Range) if x < r.head || r.last < x => + fail(s"$argValue is out of legal range ${r.head}..${r.last} for $name", args) + case Some(xs) if !xs.contains(x) => + fail(s"$argValue is not a valid choice for $name", args) + case _ => + update(x, args) + catch case _: NumberFormatException => + fail(s"$argValue is not an integer argument for $name", args) + def doSet(argRest: String) = ((implicitly[ClassTag[T]], args): @unchecked) match { case (BooleanTag, _) => update(true, args) @@ -136,23 +153,10 @@ object Settings: val output = if (isJar) JarArchive.create(path) else new PlainDirectory(path) update(output, args) } - case (IntTag, _) => - val arg2 :: args2 = if (argRest == "") args else argRest :: args - try { - val x = arg2.toInt - choices match { - case Some(r: Range) if x < r.head || r.last < x => - fail(s"$arg2 is out of legal range ${r.head}..${r.last} for $name", args2) - case Some(xs) if !xs.contains(x) => - fail(s"$arg2 is not a valid choice for $name", args) - case _ => - update(x, args2) - } - } - catch { - case _: NumberFormatException => - fail(s"$arg2 is not an integer argument for $name", args2) - } + case (IntTag, args) if argRest.nonEmpty => + setInt(argRest, args) + case (IntTag, arg2 :: args2) => + setInt(arg2, args2) case (VersionTag, _) => ScalaVersion.parse(argRest) match { case Success(v) => update(v, args) From 119735cb7b77da9cc0a18335166e0e7c5697e530 Mon Sep 17 00:00:00 2001 From: danicheg Date: Sun, 7 Nov 2021 14:26:57 +0300 Subject: [PATCH 0797/1244] Fix link in the IDE support page --- docs/docs/usage/ide-support.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/usage/ide-support.md b/docs/docs/usage/ide-support.md index eabfe29ecf49..25739b021b78 100644 --- a/docs/docs/usage/ide-support.md +++ b/docs/docs/usage/ide-support.md @@ -4,4 +4,4 @@ title: "IDE support for Scala 3" movedTo: https://docs.scala-lang.org/scala3/getting-started.html --- -This page is deprecated. Plese go to [getting-started](getting-started.md) +This page is deprecated. Please go to the [getting-started](https://docs.scala-lang.org/scala3/getting-started.html) From f027b77d1e0f3cbdf0f79479af079e1ce37cbeda Mon Sep 17 00:00:00 2001 From: danicheg Date: Sun, 7 Nov 2021 14:28:56 +0300 Subject: [PATCH 0798/1244] Fix link in the SBT projects page --- docs/docs/usage/sbt-projects.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/usage/sbt-projects.md b/docs/docs/usage/sbt-projects.md index 4b0b72f78f77..13a61eff27db 100644 --- a/docs/docs/usage/sbt-projects.md +++ b/docs/docs/usage/sbt-projects.md @@ -3,4 +3,4 @@ layout: doc-page title: "Using Dotty with sbt" --- -To try it in your project see the [Getting Started User Guide](./getting-started.md). +To try it in your project see the [Getting Started User Guide](https://docs.scala-lang.org/scala3/getting-started.html). From b6a643827b3cc3b26f8f74ca7c991c154e93c521 Mon Sep 17 00:00:00 2001 From: Ondrej Lhotak Date: Fri, 8 Oct 2021 12:04:10 +0200 Subject: [PATCH 0799/1244] enable -Yexplicit-nulls for scala3-library --- library/src/scala/IArray.scala | 31 +++++++++++-------- library/src/scala/reflect/Selectable.scala | 4 +-- library/src/scala/runtime/LazyVals.scala | 10 +++--- library/src/scala/runtime/Scala3RunTime.scala | 3 +- library/src/scala/util/FromDigits.scala | 4 +-- project/Build.scala | 1 + 6 files changed, 30 insertions(+), 23 deletions(-) diff --git a/library/src/scala/IArray.scala b/library/src/scala/IArray.scala index c5679ae7aaf9..c930fc8e4db8 100644 --- a/library/src/scala/IArray.scala +++ b/library/src/scala/IArray.scala @@ -328,54 +328,59 @@ object IArray: extension [T, U >: T: ClassTag](x: T) def +:(arr: IArray[U]): IArray[U] = genericArrayOps(arr).prepended(x) + // For backwards compatibility with code compiled without -Yexplicit-nulls + private def mapNull[A, B](a: A, f: =>B): B = + if((a: A|Null) == null) null.asInstanceOf[B] else f + /** Conversion from IArray to immutable.ArraySeq */ implicit def genericWrapArray[T](arr: IArray[T]): ArraySeq[T] = - if arr eq null then null else ArraySeq.unsafeWrapArray(arr) + mapNull(arr, ArraySeq.unsafeWrapArray(arr)) /** Conversion from IArray to immutable.ArraySeq */ implicit def wrapRefArray[T <: AnyRef](arr: IArray[T]): ArraySeq.ofRef[T] = // Since the JVM thinks arrays are covariant, one 0-length Array[AnyRef] // is as good as another for all T <: AnyRef. Instead of creating 100,000,000 // unique ones by way of this implicit, let's share one. - if (arr eq null) null - else if (arr.length == 0) ArraySeq.empty[AnyRef].asInstanceOf[ArraySeq.ofRef[T]] - else ArraySeq.ofRef(arr.asInstanceOf[Array[T]]) + mapNull(arr, + if (arr.length == 0) ArraySeq.empty[AnyRef].asInstanceOf[ArraySeq.ofRef[T]] + else ArraySeq.ofRef(arr.asInstanceOf[Array[T]]) + ) /** Conversion from IArray to immutable.ArraySeq */ implicit def wrapIntArray(arr: IArray[Int]): ArraySeq.ofInt = - if (arr ne null) new ArraySeq.ofInt(arr.asInstanceOf[Array[Int]]) else null + mapNull(arr, new ArraySeq.ofInt(arr.asInstanceOf[Array[Int]])) /** Conversion from IArray to immutable.ArraySeq */ implicit def wrapDoubleIArray(arr: IArray[Double]): ArraySeq.ofDouble = - if (arr ne null) new ArraySeq.ofDouble(arr.asInstanceOf[Array[Double]]) else null + mapNull(arr, new ArraySeq.ofDouble(arr.asInstanceOf[Array[Double]])) /** Conversion from IArray to immutable.ArraySeq */ implicit def wrapLongIArray(arr: IArray[Long]): ArraySeq.ofLong = - if (arr ne null) new ArraySeq.ofLong(arr.asInstanceOf[Array[Long]]) else null + mapNull(arr, new ArraySeq.ofLong(arr.asInstanceOf[Array[Long]])) /** Conversion from IArray to immutable.ArraySeq */ implicit def wrapFloatIArray(arr: IArray[Float]): ArraySeq.ofFloat = - if (arr ne null) new ArraySeq.ofFloat(arr.asInstanceOf[Array[Float]]) else null + mapNull(arr, new ArraySeq.ofFloat(arr.asInstanceOf[Array[Float]])) /** Conversion from IArray to immutable.ArraySeq */ implicit def wrapCharIArray(arr: IArray[Char]): ArraySeq.ofChar = - if (arr ne null) new ArraySeq.ofChar(arr.asInstanceOf[Array[Char]]) else null + mapNull(arr, new ArraySeq.ofChar(arr.asInstanceOf[Array[Char]])) /** Conversion from IArray to immutable.ArraySeq */ implicit def wrapByteIArray(arr: IArray[Byte]): ArraySeq.ofByte = - if (arr ne null) new ArraySeq.ofByte(arr.asInstanceOf[Array[Byte]]) else null + mapNull(arr, new ArraySeq.ofByte(arr.asInstanceOf[Array[Byte]])) /** Conversion from IArray to immutable.ArraySeq */ implicit def wrapShortIArray(arr: IArray[Short]): ArraySeq.ofShort = - if (arr ne null) new ArraySeq.ofShort(arr.asInstanceOf[Array[Short]]) else null + mapNull(arr, new ArraySeq.ofShort(arr.asInstanceOf[Array[Short]])) /** Conversion from IArray to immutable.ArraySeq */ implicit def wrapBooleanIArray(arr: IArray[Boolean]): ArraySeq.ofBoolean = - if (arr ne null) new ArraySeq.ofBoolean(arr.asInstanceOf[Array[Boolean]]) else null + mapNull(arr, new ArraySeq.ofBoolean(arr.asInstanceOf[Array[Boolean]])) /** Conversion from IArray to immutable.ArraySeq */ implicit def wrapUnitIArray(arr: IArray[Unit]): ArraySeq.ofUnit = - if (arr ne null) new ArraySeq.ofUnit(arr.asInstanceOf[Array[Unit]]) else null + mapNull(arr, new ArraySeq.ofUnit(arr.asInstanceOf[Array[Unit]])) /** Convert an array into an immutable array without copying, the original array * must _not_ be mutated after this or the guaranteed immutablity of IArray will diff --git a/library/src/scala/reflect/Selectable.scala b/library/src/scala/reflect/Selectable.scala index 0286eba5a35e..f0bc1f197f5d 100644 --- a/library/src/scala/reflect/Selectable.scala +++ b/library/src/scala/reflect/Selectable.scala @@ -21,7 +21,7 @@ trait Selectable extends scala.Selectable: final def selectDynamic(name: String): Any = val rcls = selectedValue.getClass try - val fld = rcls.getField(name) + val fld = rcls.getField(name).nn ensureAccessible(fld) fld.get(selectedValue) catch case ex: NoSuchFieldException => @@ -35,7 +35,7 @@ trait Selectable extends scala.Selectable: */ final def applyDynamic(name: String, paramTypes: Class[_]*)(args: Any*): Any = val rcls = selectedValue.getClass - val mth = rcls.getMethod(name, paramTypes: _*) + val mth = rcls.getMethod(name, paramTypes: _*).nn ensureAccessible(mth) mth.invoke(selectedValue, args.asInstanceOf[Seq[AnyRef]]: _*) diff --git a/library/src/scala/runtime/LazyVals.scala b/library/src/scala/runtime/LazyVals.scala index e370e3cf250d..eeb955faecae 100644 --- a/library/src/scala/runtime/LazyVals.scala +++ b/library/src/scala/runtime/LazyVals.scala @@ -7,13 +7,13 @@ import scala.language.unsafeNulls */ object LazyVals { private[this] val unsafe: sun.misc.Unsafe = - classOf[sun.misc.Unsafe].getDeclaredFields.find { field => - field.getType == classOf[sun.misc.Unsafe] && { - field.setAccessible(true) + classOf[sun.misc.Unsafe].getDeclaredFields.nn.find { field => + field.nn.getType == classOf[sun.misc.Unsafe] && { + field.nn.setAccessible(true) true } } - .map(_.get(null).asInstanceOf[sun.misc.Unsafe]) + .map(_.nn.get(null).asInstanceOf[sun.misc.Unsafe]) .getOrElse { throw new ExceptionInInitializerError { new IllegalStateException("Can't find instance of sun.misc.Unsafe") @@ -21,7 +21,7 @@ object LazyVals { } private[this] val base: Int = { - val processors = java.lang.Runtime.getRuntime.availableProcessors() + val processors = java.lang.Runtime.getRuntime.nn.availableProcessors() 8 * processors * processors } private[this] val monitors: Array[Object] = diff --git a/library/src/scala/runtime/Scala3RunTime.scala b/library/src/scala/runtime/Scala3RunTime.scala index fa141628ceec..b1645f5242aa 100644 --- a/library/src/scala/runtime/Scala3RunTime.scala +++ b/library/src/scala/runtime/Scala3RunTime.scala @@ -15,7 +15,8 @@ object Scala3RunTime: * Extracted to minimize the bytecode size at call site. */ def nn[T](x: T | Null): x.type & T = - if (x == null) throw new NullPointerException("tried to cast away nullability, but value is null") + val isNull = x == null + if (isNull) throw new NullPointerException("tried to cast away nullability, but value is null") else x.asInstanceOf[x.type & T] end Scala3RunTime diff --git a/library/src/scala/util/FromDigits.scala b/library/src/scala/util/FromDigits.scala index 1c5346ad6b97..1577f4103e03 100644 --- a/library/src/scala/util/FromDigits.scala +++ b/library/src/scala/util/FromDigits.scala @@ -135,7 +135,7 @@ object FromDigits { case ex: NumberFormatException => throw MalformedNumber() } if (x.isInfinite) throw NumberTooLarge() - if (x == 0.0f && !zeroFloat.pattern.matcher(digits).matches) throw NumberTooSmall() + if (x == 0.0f && !zeroFloat.pattern.matcher(digits).nn.matches) throw NumberTooSmall() x } @@ -153,7 +153,7 @@ object FromDigits { case ex: NumberFormatException => throw MalformedNumber() } if (x.isInfinite) throw NumberTooLarge() - if (x == 0.0d && !zeroFloat.pattern.matcher(digits).matches) throw NumberTooSmall() + if (x == 0.0d && !zeroFloat.pattern.matcher(digits).nn.matches) throw NumberTooSmall() x } diff --git a/project/Build.scala b/project/Build.scala index ff99753add6e..adbedca984dd 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -790,6 +790,7 @@ object Build { (Compile / scalacOptions) ++= Seq( // Needed so that the library sources are visible when `dotty.tools.dotc.core.Definitions#init` is called "-sourcepath", (Compile / sourceDirectories).value.map(_.getAbsolutePath).distinct.mkString(File.pathSeparator), + "-Yexplicit-nulls", ), ) From 481dfb1688b24b8ecacbed95bedffa46d0c7840f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Lhot=C3=A1k?= Date: Tue, 12 Oct 2021 10:10:19 +0200 Subject: [PATCH 0800/1244] inline mapNull to avoid creating closures Co-authored-by: Nicolas Stucki --- library/src/scala/IArray.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/scala/IArray.scala b/library/src/scala/IArray.scala index c930fc8e4db8..72124bdf8215 100644 --- a/library/src/scala/IArray.scala +++ b/library/src/scala/IArray.scala @@ -329,7 +329,7 @@ object IArray: def +:(arr: IArray[U]): IArray[U] = genericArrayOps(arr).prepended(x) // For backwards compatibility with code compiled without -Yexplicit-nulls - private def mapNull[A, B](a: A, f: =>B): B = + private inline def mapNull[A, B](a: A, inline f: B): B = if((a: A|Null) == null) null.asInstanceOf[B] else f /** Conversion from IArray to immutable.ArraySeq */ From 13a8b9f9ed88d74bdd35c92bd8049f5fc948cb88 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 3 Nov 2021 12:42:31 +0100 Subject: [PATCH 0801/1244] Disallow throws clauses over RuntimeExceptions Fixes #13846 --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 12 +++++++++--- tests/neg/i13846.check | 17 +++++++++++++++++ tests/neg/i13846.scala | 9 +++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 tests/neg/i13846.check create mode 100644 tests/neg/i13846.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index f3cfed40f6c1..878b57778de0 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1942,14 +1942,20 @@ class Typer extends Namer } var checkedArgs = preCheckKinds(args1, paramBounds) // check that arguments conform to bounds is done in phase PostTyper - if (tpt1.symbol == defn.andType) + val tycon = tpt1.symbol + if (tycon == defn.andType) checkedArgs = checkedArgs.mapconserve(arg => checkSimpleKinded(checkNoWildcard(arg))) - else if (tpt1.symbol == defn.orType) + else if (tycon == defn.orType) checkedArgs = checkedArgs.mapconserve(arg => checkSimpleKinded(checkNoWildcard(arg))) + else if tycon == defn.throwsAlias + && checkedArgs.length == 2 + && checkedArgs(1).tpe.derivesFrom(defn.RuntimeExceptionClass) + then + report.error(em"throws clause cannot be defined for RuntimeException", checkedArgs(1).srcPos) else if (ctx.isJava) - if (tpt1.symbol eq defn.ArrayClass) then + if tycon eq defn.ArrayClass then checkedArgs match { case List(arg) => val elemtp = arg.tpe.translateJavaArrayElementType diff --git a/tests/neg/i13846.check b/tests/neg/i13846.check new file mode 100644 index 000000000000..50de19874b8c --- /dev/null +++ b/tests/neg/i13846.check @@ -0,0 +1,17 @@ +-- Error: tests/neg/i13846.scala:3:22 ---------------------------------------------------------------------------------- +3 |def foo(): Int throws ArithmeticException = 1 / 0 // error + | ^^^^^^^^^^^^^^^^^^^ + | throws clause cannot be defined for RuntimeException +-- Error: tests/neg/i13846.scala:7:9 ----------------------------------------------------------------------------------- +7 | foo() // error + | ^ + | The capability to throw exception ArithmeticException is missing. + | The capability can be provided by one of the following: + | - A using clause `(using CanThrow[ArithmeticException])` + | - A `throws` clause in a result type such as `X throws ArithmeticException` + | - an enclosing `try` that catches ArithmeticException + | + | The following import might fix the problem: + | + | import unsafeExceptions.canThrowAny + | diff --git a/tests/neg/i13846.scala b/tests/neg/i13846.scala new file mode 100644 index 000000000000..ac2a8ebd8eef --- /dev/null +++ b/tests/neg/i13846.scala @@ -0,0 +1,9 @@ +import language.experimental.saferExceptions + +def foo(): Int throws ArithmeticException = 1 / 0 // error + +def test(): Unit = + try + foo() // error + catch + case _: ArithmeticException => println("Caught") From efc628ec15b9a3d658629921a8d8df4fe5c23309 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 3 Nov 2021 12:46:01 +0100 Subject: [PATCH 0802/1244] Don't generate CanThrow capabilities for catches with guards --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 2 +- tests/neg/i13849.scala | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/neg/i13849.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 878b57778de0..61cb0a9b4723 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1751,7 +1751,7 @@ class Typer extends Namer .withSpan(expr.span) val caps = for - CaseDef(pat, _, _) <- cases + case CaseDef(pat, EmptyTree, _) <- cases if Feature.enabled(Feature.saferExceptions) && pat.tpe.widen.isCheckedException yield makeCanThrow(pat.tpe.widen) caps.foldLeft(expr)((e, g) => untpd.Block(g :: Nil, e)) diff --git a/tests/neg/i13849.scala b/tests/neg/i13849.scala new file mode 100644 index 000000000000..66d5976dc08b --- /dev/null +++ b/tests/neg/i13849.scala @@ -0,0 +1,16 @@ +import annotation.experimental +import language.experimental.saferExceptions + +@experimental +case class Ex(i: Int) extends Exception(s"Exception: $i") + +@experimental +def foo(): Unit throws Ex = throw Ex(1) + +@experimental +object Main: + def main(args: Array[String]): Unit = + try + foo() // error + catch + case _: Ex if false => println("Caught") From c561ec1d561bc66f44b50b1a310cb64d482b8fca Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 3 Nov 2021 14:34:49 +0100 Subject: [PATCH 0803/1244] Restrict catch patterns under saferExceptions Restrict catch patterns to `ex: T` with no guard under saferExceptions so that capabilities can be generated safely. Fixes #13849 --- .../src/dotty/tools/dotc/typer/Checking.scala | 17 +++++++++++++++++ .../src/dotty/tools/dotc/typer/Typer.scala | 7 +++++-- tests/neg/i13849.check | 5 +++++ tests/neg/i13849.scala | 4 ++-- tests/neg/i13864.check | 18 ++++++++++++++++++ tests/neg/i13864.scala | 11 +++++++++++ 6 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 tests/neg/i13849.check create mode 100644 tests/neg/i13864.check create mode 100644 tests/neg/i13864.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 3b743906fd51..185b0584a5a2 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -33,6 +33,7 @@ import NameKinds.DefaultGetterName import NameOps._ import SymDenotations.{NoCompleter, NoDenotation} import Applications.unapplyArgs +import Inferencing.isFullyDefined import transform.patmat.SpaceEngine.isIrrefutable import config.Feature import config.Feature.sourceVersion @@ -1362,6 +1363,21 @@ trait Checking { def checkCanThrow(tp: Type, span: Span)(using Context): Unit = if Feature.enabled(Feature.saferExceptions) && tp.isCheckedException then ctx.typer.implicitArgTree(defn.CanThrowClass.typeRef.appliedTo(tp), span) + + /** Check that catch can generate a good CanThrow exception */ + def checkCatch(pat: Tree, guard: Tree)(using Context): Unit = pat match + case Typed(_: Ident, tpt) if isFullyDefined(tpt.tpe, ForceDegree.none) && guard.isEmpty => + // OK + case Bind(_, pat1) => + checkCatch(pat1, guard) + case _ => + val req = + if guard.isEmpty then "for cases of the form `ex: T` where `T` is fully defined" + else "if no pattern guard is given" + report.error( + em"""Implementation restriction: cannot generate CanThrow capability for this kind of catch. + |CanThrow capabilities can only be generated $req.""", + pat.srcPos) } trait ReChecking extends Checking { @@ -1375,6 +1391,7 @@ trait ReChecking extends Checking { override def checkMatchable(tp: Type, pos: SrcPos, pattern: Boolean)(using Context): Unit = () override def checkNoModuleClash(sym: Symbol)(using Context) = () override def checkCanThrow(tp: Type, span: Span)(using Context): Unit = () + override def checkCatch(pat: Tree, guard: Tree)(using Context): Unit = () } trait NoChecking extends ReChecking { diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 61cb0a9b4723..4c2533d6dbba 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1751,9 +1751,12 @@ class Typer extends Namer .withSpan(expr.span) val caps = for - case CaseDef(pat, EmptyTree, _) <- cases + case CaseDef(pat, guard, _) <- cases if Feature.enabled(Feature.saferExceptions) && pat.tpe.widen.isCheckedException - yield makeCanThrow(pat.tpe.widen) + yield + checkCatch(pat, guard) + makeCanThrow(pat.tpe.widen) + caps.foldLeft(expr)((e, g) => untpd.Block(g :: Nil, e)) def typedTry(tree: untpd.Try, pt: Type)(using Context): Try = { diff --git a/tests/neg/i13849.check b/tests/neg/i13849.check new file mode 100644 index 000000000000..6dafaaa30ff1 --- /dev/null +++ b/tests/neg/i13849.check @@ -0,0 +1,5 @@ +-- Error: tests/neg/i13849.scala:16:11 --------------------------------------------------------------------------------- +16 | case _: Ex if false => println("Caught") // error + | ^^^^^ + | Implementation restriction: cannot generate CanThrow capability for this kind of catch. + | CanThrow capabilities can only be generated if no pattern guard is given. diff --git a/tests/neg/i13849.scala b/tests/neg/i13849.scala index 66d5976dc08b..9b734db4be7d 100644 --- a/tests/neg/i13849.scala +++ b/tests/neg/i13849.scala @@ -11,6 +11,6 @@ def foo(): Unit throws Ex = throw Ex(1) object Main: def main(args: Array[String]): Unit = try - foo() // error + foo() catch - case _: Ex if false => println("Caught") + case _: Ex if false => println("Caught") // error diff --git a/tests/neg/i13864.check b/tests/neg/i13864.check new file mode 100644 index 000000000000..bce0788d31ce --- /dev/null +++ b/tests/neg/i13864.check @@ -0,0 +1,18 @@ +-- Error: tests/neg/i13864.scala:11:9 ---------------------------------------------------------------------------------- +11 | case Ex(i: Int) => println("Caught an Int") // error + | ^^^^^^^^^^ + | Implementation restriction: cannot generate CanThrow capability for this kind of catch. + | CanThrow capabilities can only be generated for cases of the form `ex: T` where `T` is fully defined. +-- Error: tests/neg/i13864.scala:9:10 ---------------------------------------------------------------------------------- +9 | foo(1) // error + | ^ + | The capability to throw exception Ex[Int] is missing. + | The capability can be provided by one of the following: + | - A using clause `(using CanThrow[Ex[Int]])` + | - A `throws` clause in a result type such as `X throws Ex[Int]` + | - an enclosing `try` that catches Ex[Int] + | + | The following import might fix the problem: + | + | import unsafeExceptions.canThrowAny + | diff --git a/tests/neg/i13864.scala b/tests/neg/i13864.scala new file mode 100644 index 000000000000..3053a2b12e87 --- /dev/null +++ b/tests/neg/i13864.scala @@ -0,0 +1,11 @@ +import language.experimental.saferExceptions + +case class Ex[A](a: A) extends Exception(s"Ex: $a") + +def foo[A](a: A): Unit throws Ex[A] = throw new Ex(a) + +def test(): Unit = + try + foo(1) // error + catch + case Ex(i: Int) => println("Caught an Int") // error From 9db418e97942f10c6ba4fb97da6d919735cf1fed Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 5 Nov 2021 19:17:14 +0100 Subject: [PATCH 0804/1244] Add explanation about restrictions to docs --- docs/docs/reference/experimental/canthrow.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/docs/reference/experimental/canthrow.md b/docs/docs/reference/experimental/canthrow.md index aaf637b06806..6377a040b515 100644 --- a/docs/docs/reference/experimental/canthrow.md +++ b/docs/docs/reference/experimental/canthrow.md @@ -179,6 +179,20 @@ closure may refer to capabilities in its free variables. This means that `map` i already effect polymorphic even though we did not change its signature at all. So the takeaway is that the effects as capabilities model naturally provides for effect polymorphism whereas this is something that other approaches struggle with. +**Note 1:** The compiler will only treat checked exceptions that way. An exception type is _checked_ if it is a subtype of +`Exception` but not of `RuntimeException`. The signature of `CanThrow` still admits `RuntimeException`s since `RuntimeException` is a proper subtype of its bound, `Exception`. But no capabilities will be generated for `RuntimeException`s. Furthermore, `throws` clauses +also may not refer to `RuntimeException`s. + +**Note 2:** To keep things simple, the compiler will currently only generate capabilities +for catch clauses of the form +```scala + case ex: Ex => +``` +where `ex` is an arbitrary variable name (`_` is also allowed), and `Ex` is an arbitrary +checked exception type. Constructor patterns such as `Ex(...)` or patterns with guards +are not allowed. The compiler will issue an error if one of these is used to catch +a checked exception and `saferExceptions` is enabled. + ## Gradual Typing Via Imports Another advantage is that the model allows a gradual migration from current unchecked exceptions to safer exceptions. Imagine for a moment that `experimental.saferExceptions` is turned on everywhere. There would be lots of code that breaks since functions have not yet been properly annotated with `throws`. But it's easy to create an escape hatch that lets us ignore the breakages for a while: simply add the import From 7a3cec0f14f25f43a75c2037d7deb824c501ca04 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 3 Nov 2021 16:15:00 +0100 Subject: [PATCH 0805/1244] Add missing position when expanding `error` Closes #13871. This issue was already fixed but failed `-Ycheck` due to the missing position. --- compiler/src/dotty/tools/dotc/typer/Inliner.scala | 6 +++--- compiler/test/dotc/pos-test-pickling.blacklist | 1 + tests/pos/i13871.scala | 10 ++++++++++ 3 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 tests/pos/i13871.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index b4264dee6e64..4fede9b6b9e4 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -367,9 +367,9 @@ object Inliner { lit(error.pos.column), if kind == ErrorKind.Parser then parserErrorKind else typerErrorKind) - private def packErrors(errors: List[(ErrorKind, Error)])(using Context): Tree = + private def packErrors(errors: List[(ErrorKind, Error)], pos: SrcPos)(using Context): Tree = val individualErrors: List[Tree] = errors.map(packError) - val errorTpt = ref(defn.CompiletimeTesting_ErrorClass) + val errorTpt = ref(defn.CompiletimeTesting_ErrorClass).withSpan(pos.span) mkList(individualErrors, errorTpt) /** Expand call to scala.compiletime.testing.typeChecks */ @@ -380,7 +380,7 @@ object Inliner { /** Expand call to scala.compiletime.testing.typeCheckErrors */ def typeCheckErrors(tree: Tree)(using Context): Tree = val errors = compileForErrors(tree) - packErrors(errors) + packErrors(errors, tree) /** Expand call to scala.compiletime.codeOf */ def codeOf(arg: Tree, pos: SrcPos)(using Context): Tree = diff --git a/compiler/test/dotc/pos-test-pickling.blacklist b/compiler/test/dotc/pos-test-pickling.blacklist index 7136b2f7ac74..9c94e5968fce 100644 --- a/compiler/test/dotc/pos-test-pickling.blacklist +++ b/compiler/test/dotc/pos-test-pickling.blacklist @@ -17,6 +17,7 @@ i7740a.scala i7740b.scala i6507b.scala i12299a.scala +i13871.scala # Tree is huge and blows stack for printing Text i7034.scala diff --git a/tests/pos/i13871.scala b/tests/pos/i13871.scala new file mode 100644 index 000000000000..3b1ed0f1f06c --- /dev/null +++ b/tests/pos/i13871.scala @@ -0,0 +1,10 @@ +import scala.compiletime.{error, codeOf} +import scala.compiletime.testing.* + +inline def testError(inline typeName: Any): String = error("Got error " + codeOf(typeName)) + +transparent inline def compileErrors(inline code: String): List[Error] = typeCheckErrors(code) + +def test = + typeCheckErrors("""testError("string")""") + compileErrors("""testError("string")""") From cb1e2866984e12806359181308b213002e523843 Mon Sep 17 00:00:00 2001 From: Eric Torreborre Date: Thu, 21 Oct 2021 10:25:11 +0200 Subject: [PATCH 0806/1244] added specs2 --- .gitmodules | 3 +++ community-build/community-projects/specs2 | 1 + .../src/scala/dotty/communitybuild/projects.scala | 8 ++++++++ .../scala/dotty/communitybuild/CommunityBuildTest.scala | 1 + 4 files changed, 13 insertions(+) create mode 160000 community-build/community-projects/specs2 diff --git a/.gitmodules b/.gitmodules index 1b50ef1cc54b..2977e923b55e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -213,3 +213,6 @@ [submodule "community-build/community-projects/scala-java8-compat"] path = community-build/community-projects/scala-java8-compat url = https://github.com/dotty-staging/scala-java8-compat.git +[submodule "community-build/community-projects/specs2"] + path = community-build/community-projects/specs2 + url = https://github.com/etorreborre/specs2.git diff --git a/community-build/community-projects/specs2 b/community-build/community-projects/specs2 new file mode 160000 index 000000000000..0652daeefb57 --- /dev/null +++ b/community-build/community-projects/specs2 @@ -0,0 +1 @@ +Subproject commit 0652daeefb57c2d51e3f16ea5c44929bdba722bf diff --git a/community-build/src/scala/dotty/communitybuild/projects.scala b/community-build/src/scala/dotty/communitybuild/projects.scala index 6d31cd73b54c..c258154a5c20 100644 --- a/community-build/src/scala/dotty/communitybuild/projects.scala +++ b/community-build/src/scala/dotty/communitybuild/projects.scala @@ -731,6 +731,13 @@ object projects: dependencies = List(scalaJava8Compat, scalatest) ) + lazy val specs2 = SbtCommunityProject( + project = "specs2", + sbtTestCommand = "core/test", + sbtPublishCommand = "core/publishLocal", + dependencies = List() + ) + end projects def allProjects = List( @@ -809,6 +816,7 @@ def allProjects = List( projects.fs2, projects.libretto, projects.jacksonModuleScala, + projects.specs2, ) lazy val projectMap = allProjects.groupBy(_.project) diff --git a/community-build/test/scala/dotty/communitybuild/CommunityBuildTest.scala b/community-build/test/scala/dotty/communitybuild/CommunityBuildTest.scala index c1d748b4d3ad..9b5c17e85965 100644 --- a/community-build/test/scala/dotty/communitybuild/CommunityBuildTest.scala +++ b/community-build/test/scala/dotty/communitybuild/CommunityBuildTest.scala @@ -91,6 +91,7 @@ class CommunityBuildTestC: @Test def sconfig = projects.sconfig.run() @Test def shapeless = projects.shapeless.run() @Test def sourcecode = projects.sourcecode.run() + @Test def specs2 = projects.specs2.run() @Test def stdLib213 = projects.stdLib213.run() @Test def ujson = projects.ujson.run() @Test def upickle = projects.upickle.run() From e227571e4a51716ec43788cc01952ab63fdcaa84 Mon Sep 17 00:00:00 2001 From: Eric Torreborre Date: Thu, 4 Nov 2021 09:58:17 +0100 Subject: [PATCH 0807/1244] exclude some specs2 tests from CI --- community-build/src/scala/dotty/communitybuild/projects.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/community-build/src/scala/dotty/communitybuild/projects.scala b/community-build/src/scala/dotty/communitybuild/projects.scala index c258154a5c20..61c72f8088f0 100644 --- a/community-build/src/scala/dotty/communitybuild/projects.scala +++ b/community-build/src/scala/dotty/communitybuild/projects.scala @@ -733,7 +733,7 @@ object projects: lazy val specs2 = SbtCommunityProject( project = "specs2", - sbtTestCommand = "core/test", + sbtTestCommand = "core/testOnly -- exclude ci", sbtPublishCommand = "core/publishLocal", dependencies = List() ) From 607a1ca7f576ac5150b9ad8afe34ac0941627e3b Mon Sep 17 00:00:00 2001 From: Eric Torreborre Date: Tue, 9 Nov 2021 09:27:22 +0100 Subject: [PATCH 0808/1244] use the https://github.com/dotty-staging/specs2 repo as a submodule --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 2977e923b55e..d93aab9aa8fe 100644 --- a/.gitmodules +++ b/.gitmodules @@ -215,4 +215,4 @@ url = https://github.com/dotty-staging/scala-java8-compat.git [submodule "community-build/community-projects/specs2"] path = community-build/community-projects/specs2 - url = https://github.com/etorreborre/specs2.git + url = https://github.com/dotty-staging/specs2.git From 399c3d1e483c34f170d620aa5a871e08b688ab8b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 5 Nov 2021 15:00:33 +0100 Subject: [PATCH 0809/1244] Impose implicit search limit Impose a configurable limit on the total number of nodes constructed during an implicit search. Fixes #13838 --- .../tools/dotc/config/ScalaSettings.scala | 1 + .../dotty/tools/dotc/typer/Implicits.scala | 47 ++++++++++++++++--- .../dotty/tools/dotc/CompilationTests.scala | 1 + tests/neg-custom-args/i13838.check | 18 +++++++ tests/neg-custom-args/i13838.scala | 40 ++++++++++++++++ 5 files changed, 101 insertions(+), 6 deletions(-) create mode 100644 tests/neg-custom-args/i13838.check create mode 100644 tests/neg-custom-args/i13838.scala diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 6147cd78f3e6..7f8c1a53bec3 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -218,6 +218,7 @@ private sealed trait XSettings: val Xtarget: Setting[String] = ChoiceSetting("-Xtarget", "target", "Emit bytecode for the specified version of the Java platform. This might produce bytecode that will break at runtime. When on JDK 9+, consider -release as a safer alternative.", ScalaSettings.supportedTargetVersions, "", aliases = List("--Xtarget")) val XcheckMacros: Setting[Boolean] = BooleanSetting("-Xcheck-macros", "Check some invariants of macro generated code while expanding macros", aliases = List("--Xcheck-macros")) val XmainClass: Setting[String] = StringSetting("-Xmain-class", "path", "Class for manifest's Main-Class entry (only useful with -d )", "") + val XimplicitSearchLimit: Setting[Int] = IntSetting("-Ximplicit-search-limit", "Maximal number of expressions to be generated in an implicit search", 100000) val XmixinForceForwarders = ChoiceSetting( name = "-Xmixin-force-forwarders", diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 6c24dc6be119..fd2adc0358de 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -489,6 +489,11 @@ object Implicits: @sharable val NoMatchingImplicitsFailure: SearchFailure = SearchFailure(NoMatchingImplicits, NoSpan)(using NoContext) + @sharable object ImplicitSearchTooLarge extends NoMatchingImplicits(NoType, EmptyTree, OrderingConstraint.empty) + + @sharable val ImplicitSearchTooLargeFailure: SearchFailure = + SearchFailure(ImplicitSearchTooLarge, NoSpan)(using NoContext) + /** An ambiguous implicits failure */ class AmbiguousImplicits(val alt1: SearchSuccess, val alt2: SearchSuccess, val expectedType: Type, val argument: Tree) extends SearchFailureType { def explanation(using Context): String = @@ -1129,18 +1134,44 @@ trait Implicits: val isNotGiven: Boolean = wildProto.classSymbol == defn.NotGivenClass + private def searchTooLarge(): Boolean = ctx.searchHistory match + case root: SearchRoot => + root.nestedSearches = 1 + false + case h => + val limit = ctx.settings.XimplicitSearchLimit.value + val nestedSearches = h.root.nestedSearches + val result = nestedSearches > limit + if result then + var c = ctx + while c.outer.typer eq ctx.typer do c = c.outer + report.echo( + em"""Implicit search problem too large. + |an implicit search was terminated with failure after trying $limit expressions. + | + |You can change the behavior by setting the `-Ximplicit-search-limit` value. + |Smaller values cause the search to fail faster. + |Larger values might make a very large search problem succeed. + |""", + ctx.source.atSpan(span))(using c) + else + h.root.nestedSearches = nestedSearches + 1 + result + /** Try to type-check implicit reference, after checking that this is not * a diverging search */ def tryImplicit(cand: Candidate, contextual: Boolean): SearchResult = if checkDivergence(cand) then SearchFailure(new DivergingImplicit(cand.ref, wideProto, argument), span) - else { + else if searchTooLarge() then + ImplicitSearchTooLargeFailure + else val history = ctx.searchHistory.nest(cand, pt) val typingCtx = nestedContext().setNewTyperState().setFreshGADTBounds.setSearchHistory(history) val result = typedImplicit(cand, pt, argument, span)(using typingCtx) - result match { + result match case res: SearchSuccess => ctx.searchHistory.defineBynameImplicit(wideProto, res) case _ => @@ -1152,8 +1183,6 @@ trait Implicits: // tests/neg/implicitSearch.check typingCtx.typerState.gc() result - } - } /** Search a list of eligible implicit references */ private def searchImplicit(eligible: List[Candidate], contextual: Boolean): SearchResult = @@ -1242,7 +1271,9 @@ trait Implicits: negateIfNot(tryImplicit(cand, contextual)) match { case fail: SearchFailure => - if (fail.isAmbiguous) + if fail eq ImplicitSearchTooLargeFailure then + fail + else if (fail.isAmbiguous) if migrateTo3 then val result = rank(remaining, found, NoMatchingImplicitsFailure :: rfailures) if (result.isSuccess) @@ -1610,13 +1641,17 @@ case class OpenSearch(cand: Candidate, pt: Type, outer: SearchHistory)(using Con end OpenSearch /** - * The the state corresponding to the outermost context of an implicit searcch. + * The state corresponding to the outermost context of an implicit searcch. */ final class SearchRoot extends SearchHistory: val root = this val byname = false def openSearchPairs = Nil + /** How many expressions were constructed so far in the current toplevel implicit search? + */ + var nestedSearches: Int = 0 + /** The dictionary of recursive implicit types and corresponding terms for this search. */ var myImplicitDictionary: mutable.Map[Type, (TermRef, tpd.Tree)] = null private def implicitDictionary = diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index a9f376d3cda6..06526aa6a924 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -183,6 +183,7 @@ class CompilationTests { compileFile("tests/neg-custom-args/feature-shadowing.scala", defaultOptions.and("-Xfatal-warnings", "-feature")), compileDir("tests/neg-custom-args/hidden-type-errors", defaultOptions.and("-explain")), compileFile("tests/neg-custom-args/i13026.scala", defaultOptions.and("-print-lines")), + compileFile("tests/neg-custom-args/i13838.scala", defaultOptions.and("-Ximplicit-search-limit", "1000")), ).checkExpectedErrors() } diff --git a/tests/neg-custom-args/i13838.check b/tests/neg-custom-args/i13838.check new file mode 100644 index 000000000000..e6e5a0eb9e2e --- /dev/null +++ b/tests/neg-custom-args/i13838.check @@ -0,0 +1,18 @@ +-- [E007] Type Mismatch Error: tests/neg-custom-args/i13838.scala:8:48 ------------------------------------------------- +8 | def liftF[F[_], A](fa: F[A]): F[Foo[A]] = map(fa)(???) // error + | ^^ + | Found: (fa : F[A]) + | Required: F²[Foo[A²]] + | + | where: A is a type in method liftF + | A² is a type variable + | F is a type in method liftF with bounds <: [_] =>> Any + | F² is a type variable with constraint <: [_] =>> Any + | + | + | The following import might make progress towards fixing the problem: + | + | import collection.Searching.search + | + +longer explanation available when compiling with `-explain` diff --git a/tests/neg-custom-args/i13838.scala b/tests/neg-custom-args/i13838.scala new file mode 100644 index 000000000000..92e7a6d48439 --- /dev/null +++ b/tests/neg-custom-args/i13838.scala @@ -0,0 +1,40 @@ +implicit def catsSyntaxEq[A: Eq](a: A): Foo[A] = ??? + +class Foo[A] +object Foo: + given [A: Eq]: Eq[Foo[A]] = ??? + +object FooT: + def liftF[F[_], A](fa: F[A]): F[Foo[A]] = map(fa)(???) // error + + def map[F[_], A](ffa: F[Foo[A]])(f: A): Nothing = ??? + + given OrderFFooA[F[_], A](using Ord: Order[F[Foo[A]]]): Order[F[Foo[A]]] = ??? + +trait Eq[A] +trait Order[A] extends Eq[A] + +object Eq { + given catsKernelOrderForTuple1[A0](using A0: Order[A0]): Order[Tuple1[A0]] = ??? + given catsKernelOrderForTuple2[A0, A1](using A0: Order[A0], A1: Order[A1]): Order[(A0, A1)] = ??? + given catsKernelOrderForTuple3[A0, A1, A2](using A0: Order[A0], A1: Order[A1], A2: Order[A2]): Order[(A0, A1, A2)] = ??? + given catsKernelOrderForTuple4[A0, A1, A2, A3](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3]): Order[(A0, A1, A2, A3)] = ??? + given catsKernelOrderForTuple5[A0, A1, A2, A3, A4](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4]): Order[(A0, A1, A2, A3, A4)] = ??? + given catsKernelOrderForTuple6[A0, A1, A2, A3, A4, A5](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5]): Order[(A0, A1, A2, A3, A4, A5)] = ??? + given catsKernelOrderForTuple7[A0, A1, A2, A3, A4, A5, A6](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6]): Order[(A0, A1, A2, A3, A4, A5, A6)] = ??? + given catsKernelOrderForTuple8[A0, A1, A2, A3, A4, A5, A6, A7](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7]): Order[(A0, A1, A2, A3, A4, A5, A6, A7)] = ??? + given catsKernelOrderForTuple9[A0, A1, A2, A3, A4, A5, A6, A7, A8](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8)] = ??? + given catsKernelOrderForTuple10[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9)] = ??? + given catsKernelOrderForTuple11[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)] = ??? + given catsKernelOrderForTuple12[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11)] = ??? + given catsKernelOrderForTuple13[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12)] = ??? + given catsKernelOrderForTuple14[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12], A13: Order[A13]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13)] = ??? + given catsKernelOrderForTuple15[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12], A13: Order[A13], A14: Order[A14]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14)] = ??? + given catsKernelOrderForTuple16[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12], A13: Order[A13], A14: Order[A14], A15: Order[A15]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15)] = ??? + given catsKernelOrderForTuple17[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12], A13: Order[A13], A14: Order[A14], A15: Order[A15], A16: Order[A16]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16)] = ??? + given catsKernelOrderForTuple18[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12], A13: Order[A13], A14: Order[A14], A15: Order[A15], A16: Order[A16], A17: Order[A17]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17)] = ??? + given catsKernelOrderForTuple19[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12], A13: Order[A13], A14: Order[A14], A15: Order[A15], A16: Order[A16], A17: Order[A17], A18: Order[A18]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18)] = ??? + given catsKernelOrderForTuple20[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12], A13: Order[A13], A14: Order[A14], A15: Order[A15], A16: Order[A16], A17: Order[A17], A18: Order[A18], A19: Order[A19]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19)] = ??? + given catsKernelOrderForTuple21[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12], A13: Order[A13], A14: Order[A14], A15: Order[A15], A16: Order[A16], A17: Order[A17], A18: Order[A18], A19: Order[A19], A20: Order[A20]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20)] = ??? + given catsKernelOrderForTuple22[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21](using A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12], A13: Order[A13], A14: Order[A14], A15: Order[A15], A16: Order[A16], A17: Order[A17], A18: Order[A18], A19: Order[A19], A20: Order[A20], A21: Order[A21]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21)] = ??? +} From 6a78bb35f83e81946ce59607ba2bb9c0852e0fad Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 5 Nov 2021 16:44:29 +0100 Subject: [PATCH 0810/1244] Issue "search too large" as warnings that cannot be hidden --- .../dotty/tools/dotc/reporting/ErrorMessageID.scala | 3 ++- .../src/dotty/tools/dotc/reporting/Message.scala | 7 +++++++ .../dotc/reporting/UniqueMessagePositions.scala | 13 +++++++++---- .../src/dotty/tools/dotc/reporting/messages.scala | 12 ++++++++++++ compiler/src/dotty/tools/dotc/typer/Implicits.scala | 10 +--------- tests/neg-custom-args/i13838.check | 9 +++++++++ 6 files changed, 40 insertions(+), 14 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala index 342e640ca819..f55196f82a8e 100644 --- a/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala +++ b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala @@ -175,7 +175,8 @@ enum ErrorMessageID extends java.lang.Enum[ErrorMessageID]: OverrideErrorID, MatchableWarningID, CannotExtendFunctionID, - LossyWideningConstantConversionID + LossyWideningConstantConversionID, + ImplicitSearchTooLargeID def errorNumber = ordinal - 2 diff --git a/compiler/src/dotty/tools/dotc/reporting/Message.scala b/compiler/src/dotty/tools/dotc/reporting/Message.scala index 8ce94f4fa3a3..cd7456cafcc2 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Message.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Message.scala @@ -124,6 +124,13 @@ abstract class Message(val errorId: ErrorMessageID) { self => def explain = self.explain ++ suffix override def canExplain = true + /** Override with `true` for messages that should always be shown even if their + * position overlaps another messsage of a different class. On the other hand + * multiple messages of the same class with overlapping positions will lead + * to only a single message of that class to be issued. + */ + def showAlways = false + override def toString = msg } diff --git a/compiler/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala b/compiler/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala index fb4c92c12f83..e4312f46f779 100644 --- a/compiler/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala +++ b/compiler/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala @@ -10,19 +10,24 @@ import core.Contexts._ * are suppressed, unless they are of increasing severity. */ trait UniqueMessagePositions extends Reporter { - private val positions = new mutable.HashMap[(SourceFile, Int), Int] + private val positions = new mutable.HashMap[(SourceFile, Int), Diagnostic] /** Logs a position and returns true if it was already logged. * @note Two positions are considered identical for logging if they have the same point. */ override def isHidden(dia: Diagnostic)(using Context): Boolean = + extension (dia1: Diagnostic) def hides(dia2: Diagnostic): Boolean = + if dia2.msg.showAlways then dia1.msg.getClass == dia2.msg.getClass + else dia1.level >= dia2.level super.isHidden(dia) || { - dia.pos.exists && !ctx.settings.YshowSuppressedErrors.value && { + dia.pos.exists + && !ctx.settings.YshowSuppressedErrors.value + && { var shouldHide = false for (pos <- dia.pos.start to dia.pos.end) positions get (ctx.source, pos) match { - case Some(level) if level >= dia.level => shouldHide = true - case _ => positions((ctx.source, pos)) = dia.level + case Some(dia1) if dia1.hides(dia) => shouldHide = true + case _ => positions((ctx.source, pos)) = dia } shouldHide } diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index 62bf295fed8c..398827f1a279 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -2515,3 +2515,15 @@ import transform.SymUtils._ |Inlining such definition would multiply this footprint for each call site. |""".stripMargin } + + class ImplicitSearchTooLargeWarning(limit: Int)(using Context) extends TypeMsg(ImplicitSearchTooLargeID): + override def showAlways = true + def msg = + em"""Implicit search problem too large. + |an implicit search was terminated with failure after trying $limit expressions. + | + |You can change the behavior by setting the `-Ximplicit-search-limit` value. + |Smaller values cause the search to fail faster. + |Larger values might make a very large search problem succeed. + |""" + def explain = "" \ No newline at end of file diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index fd2adc0358de..51a9ddfbda16 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -1145,15 +1145,7 @@ trait Implicits: if result then var c = ctx while c.outer.typer eq ctx.typer do c = c.outer - report.echo( - em"""Implicit search problem too large. - |an implicit search was terminated with failure after trying $limit expressions. - | - |You can change the behavior by setting the `-Ximplicit-search-limit` value. - |Smaller values cause the search to fail faster. - |Larger values might make a very large search problem succeed. - |""", - ctx.source.atSpan(span))(using c) + report.warning(ImplicitSearchTooLargeWarning(limit), ctx.source.atSpan(span))(using c) else h.root.nestedSearches = nestedSearches + 1 result diff --git a/tests/neg-custom-args/i13838.check b/tests/neg-custom-args/i13838.check index e6e5a0eb9e2e..8d51bbc36f81 100644 --- a/tests/neg-custom-args/i13838.check +++ b/tests/neg-custom-args/i13838.check @@ -16,3 +16,12 @@ | longer explanation available when compiling with `-explain` +-- [E168] Type Warning: tests/neg-custom-args/i13838.scala:8:50 -------------------------------------------------------- +8 | def liftF[F[_], A](fa: F[A]): F[Foo[A]] = map(fa)(???) // error + | ^ + | Implicit search problem too large. + | an implicit search was terminated with failure after trying 1000 expressions. + | + | You can change the behavior by setting the `-Ximplicit-search-limit` value. + | Smaller values cause the search to fail faster. + | Larger values might make a very large search problem succeed. From 4b0dc7589ddefed3893e39c4a451689883b3fd8f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 6 Nov 2021 11:37:10 +0100 Subject: [PATCH 0811/1244] Give more information when "search too large" is hit - show what the root query was - under -explain, show the trace until the overflow occurred. --- .../dotty/tools/dotc/reporting/messages.scala | 16 ++++++++++++++-- .../src/dotty/tools/dotc/typer/Implicits.scala | 2 +- tests/neg-custom-args/i13838.check | 5 +++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index 398827f1a279..4a1efab782a1 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -18,6 +18,7 @@ import ast.Trees import config.{Feature, ScalaVersion} import typer.ErrorReporting.{err, matchReductionAddendum} import typer.ProtoTypes.ViewProto +import typer.Implicits.Candidate import scala.util.control.NonFatal import StdNames.nme import printing.Formatting.hl @@ -2516,14 +2517,25 @@ import transform.SymUtils._ |""".stripMargin } - class ImplicitSearchTooLargeWarning(limit: Int)(using Context) extends TypeMsg(ImplicitSearchTooLargeID): + class ImplicitSearchTooLargeWarning(limit: Int, openSearchPairs: List[(Candidate, Type)])(using Context) + extends TypeMsg(ImplicitSearchTooLargeID): override def showAlways = true + def showQuery(query: (Candidate, Type)): String = + i" ${query._1.ref.symbol.showLocated} for ${query._2}}" def msg = em"""Implicit search problem too large. |an implicit search was terminated with failure after trying $limit expressions. + |The root candidate for the search was: + | + |${showQuery(openSearchPairs.last)} | |You can change the behavior by setting the `-Ximplicit-search-limit` value. |Smaller values cause the search to fail faster. |Larger values might make a very large search problem succeed. |""" - def explain = "" \ No newline at end of file + def explain = + em"""The overflow happened with the following lists of tried expressions and target types, + |starting with the root query: + | + |${openSearchPairs.reverse.map(showQuery)}%\n% + """ diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 51a9ddfbda16..84a913b47f58 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -1145,7 +1145,7 @@ trait Implicits: if result then var c = ctx while c.outer.typer eq ctx.typer do c = c.outer - report.warning(ImplicitSearchTooLargeWarning(limit), ctx.source.atSpan(span))(using c) + report.warning(ImplicitSearchTooLargeWarning(limit, h.openSearchPairs), ctx.source.atSpan(span))(using c) else h.root.nestedSearches = nestedSearches + 1 result diff --git a/tests/neg-custom-args/i13838.check b/tests/neg-custom-args/i13838.check index 8d51bbc36f81..9b77e1566c16 100644 --- a/tests/neg-custom-args/i13838.check +++ b/tests/neg-custom-args/i13838.check @@ -21,7 +21,12 @@ longer explanation available when compiling with `-explain` | ^ | Implicit search problem too large. | an implicit search was terminated with failure after trying 1000 expressions. + | The root candidate for the search was: + | + | method catsSyntaxEq for ([_] =>> Any)[Foo[Any]]} | | You can change the behavior by setting the `-Ximplicit-search-limit` value. | Smaller values cause the search to fail faster. | Larger values might make a very large search problem succeed. + +longer explanation available when compiling with `-explain` From 3be5520d360041b24702661b4bf85838250f3a9a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 9 Nov 2021 11:59:51 +0100 Subject: [PATCH 0812/1244] Reduce limit for implicit search too large Half the limit so that we fail in a bit less than a minute instead of more than 5 minutes. --- compiler/src/dotty/tools/dotc/config/ScalaSettings.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 7f8c1a53bec3..d66c5d7ab4c2 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -218,7 +218,7 @@ private sealed trait XSettings: val Xtarget: Setting[String] = ChoiceSetting("-Xtarget", "target", "Emit bytecode for the specified version of the Java platform. This might produce bytecode that will break at runtime. When on JDK 9+, consider -release as a safer alternative.", ScalaSettings.supportedTargetVersions, "", aliases = List("--Xtarget")) val XcheckMacros: Setting[Boolean] = BooleanSetting("-Xcheck-macros", "Check some invariants of macro generated code while expanding macros", aliases = List("--Xcheck-macros")) val XmainClass: Setting[String] = StringSetting("-Xmain-class", "path", "Class for manifest's Main-Class entry (only useful with -d )", "") - val XimplicitSearchLimit: Setting[Int] = IntSetting("-Ximplicit-search-limit", "Maximal number of expressions to be generated in an implicit search", 100000) + val XimplicitSearchLimit: Setting[Int] = IntSetting("-Ximplicit-search-limit", "Maximal number of expressions to be generated in an implicit search", 50000) val XmixinForceForwarders = ChoiceSetting( name = "-Xmixin-force-forwarders", From c439dd1cfd5610a123ffd9be0a39dd70a2a81a0c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 9 Nov 2021 12:34:07 +0100 Subject: [PATCH 0813/1244] Refine checking for underspecified implicit queries - Use the wildcard approximation instead of the original type since that one determined what is eligible, and the goal is to refuse the search if everything is eligible. - Also refuse underspecified implicit parameters, not just conversions. - Treat wildcard types as underspecified. Two tests had to be reclassified. But the original tests were not meant to compile anyway. They were bout misleading error messages (no longer the case) and crashers. --- .../dotty/tools/dotc/typer/Implicits.scala | 68 +++++++++++-------- .../dotty/tools/dotc/CompilationTests.scala | 1 - tests/neg-custom-args/i13838.check | 32 --------- tests/{pos => neg}/i10082.scala | 0 tests/{neg-custom-args => neg}/i13838.scala | 0 tests/neg/i13838a.scala | 47 +++++++++++++ tests/{pos => neg}/i7745.scala | 2 +- 7 files changed, 86 insertions(+), 64 deletions(-) delete mode 100644 tests/neg-custom-args/i13838.check rename tests/{pos => neg}/i10082.scala (100%) rename tests/{neg-custom-args => neg}/i13838.scala (100%) create mode 100644 tests/neg/i13838a.scala rename tests/{pos => neg}/i7745.scala (72%) diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 84a913b47f58..a3b0dd02714d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -795,16 +795,8 @@ trait Implicits: */ def inferView(from: Tree, to: Type)(using Context): SearchResult = { record("inferView") - val wfromtp = from.tpe.widen - if to.isAny - || to.isAnyRef - || to.isRef(defn.UnitClass) - || wfromtp.isRef(defn.NothingClass) - || wfromtp.isRef(defn.NullClass) - || !ctx.mode.is(Mode.ImplicitsEnabled) - || from.isInstanceOf[Super] - || (wfromtp eq NoPrefix) - then NoMatchingImplicitsFailure + if !ctx.mode.is(Mode.ImplicitsEnabled) || from.isInstanceOf[Super] then + NoMatchingImplicitsFailure else { def adjust(to: Type) = to.stripTypeVar.widenExpr match { case SelectionProto(name, memberProto, compat, true) => @@ -1434,27 +1426,43 @@ trait Implicits: rank(sort(eligible), NoMatchingImplicitsFailure, Nil) end searchImplicit + def isUnderSpecifiedArgument(tp: Type): Boolean = + tp.isRef(defn.NothingClass) || tp.isRef(defn.NullClass) || (tp eq NoPrefix) + + private def isUnderspecified(tp: Type): Boolean = tp.stripTypeVar match + case tp: WildcardType => + !tp.optBounds.exists || isUnderspecified(tp.optBounds.hiBound) + case tp: ViewProto => + isUnderspecified(tp.resType) + || tp.resType.isRef(defn.UnitClass) + || isUnderSpecifiedArgument(tp.argType.widen) + case _ => + tp.isAny || tp.isAnyRef + private def searchImplicit(contextual: Boolean): SearchResult = - val eligible = - if contextual then ctx.implicits.eligible(wildProto) - else implicitScope(wildProto).eligible - searchImplicit(eligible, contextual) match - case result: SearchSuccess => - result - case failure: SearchFailure => - failure.reason match - case _: AmbiguousImplicits => failure - case reason => - if contextual then - searchImplicit(contextual = false).recoverWith { - failure2 => failure2.reason match - case _: AmbiguousImplicits => failure2 - case _ => - reason match - case (_: DivergingImplicit) => failure - case _ => List(failure, failure2).maxBy(_.tree.treeSize) - } - else failure + if isUnderspecified(wildProto) then + NoMatchingImplicitsFailure + else + val eligible = + if contextual then ctx.implicits.eligible(wildProto) + else implicitScope(wildProto).eligible + searchImplicit(eligible, contextual) match + case result: SearchSuccess => + result + case failure: SearchFailure => + failure.reason match + case _: AmbiguousImplicits => failure + case reason => + if contextual then + searchImplicit(contextual = false).recoverWith { + failure2 => failure2.reason match + case _: AmbiguousImplicits => failure2 + case _ => + reason match + case (_: DivergingImplicit) => failure + case _ => List(failure, failure2).maxBy(_.tree.treeSize) + } + else failure end searchImplicit /** Find a unique best implicit reference */ diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index 06526aa6a924..a9f376d3cda6 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -183,7 +183,6 @@ class CompilationTests { compileFile("tests/neg-custom-args/feature-shadowing.scala", defaultOptions.and("-Xfatal-warnings", "-feature")), compileDir("tests/neg-custom-args/hidden-type-errors", defaultOptions.and("-explain")), compileFile("tests/neg-custom-args/i13026.scala", defaultOptions.and("-print-lines")), - compileFile("tests/neg-custom-args/i13838.scala", defaultOptions.and("-Ximplicit-search-limit", "1000")), ).checkExpectedErrors() } diff --git a/tests/neg-custom-args/i13838.check b/tests/neg-custom-args/i13838.check deleted file mode 100644 index 9b77e1566c16..000000000000 --- a/tests/neg-custom-args/i13838.check +++ /dev/null @@ -1,32 +0,0 @@ --- [E007] Type Mismatch Error: tests/neg-custom-args/i13838.scala:8:48 ------------------------------------------------- -8 | def liftF[F[_], A](fa: F[A]): F[Foo[A]] = map(fa)(???) // error - | ^^ - | Found: (fa : F[A]) - | Required: F²[Foo[A²]] - | - | where: A is a type in method liftF - | A² is a type variable - | F is a type in method liftF with bounds <: [_] =>> Any - | F² is a type variable with constraint <: [_] =>> Any - | - | - | The following import might make progress towards fixing the problem: - | - | import collection.Searching.search - | - -longer explanation available when compiling with `-explain` --- [E168] Type Warning: tests/neg-custom-args/i13838.scala:8:50 -------------------------------------------------------- -8 | def liftF[F[_], A](fa: F[A]): F[Foo[A]] = map(fa)(???) // error - | ^ - | Implicit search problem too large. - | an implicit search was terminated with failure after trying 1000 expressions. - | The root candidate for the search was: - | - | method catsSyntaxEq for ([_] =>> Any)[Foo[Any]]} - | - | You can change the behavior by setting the `-Ximplicit-search-limit` value. - | Smaller values cause the search to fail faster. - | Larger values might make a very large search problem succeed. - -longer explanation available when compiling with `-explain` diff --git a/tests/pos/i10082.scala b/tests/neg/i10082.scala similarity index 100% rename from tests/pos/i10082.scala rename to tests/neg/i10082.scala diff --git a/tests/neg-custom-args/i13838.scala b/tests/neg/i13838.scala similarity index 100% rename from tests/neg-custom-args/i13838.scala rename to tests/neg/i13838.scala diff --git a/tests/neg/i13838a.scala b/tests/neg/i13838a.scala new file mode 100644 index 000000000000..9fcb7be7bdcf --- /dev/null +++ b/tests/neg/i13838a.scala @@ -0,0 +1,47 @@ +object TooSlow { + trait EqSyntax { + implicit def catsSyntaxEq[A: Eq](a: A): EqOps[A] = ??? + } + + final class EqOps[A] + + object eq extends EqSyntax + + import eq._ + + sealed abstract class Foo[A] + object Foo { + implicit def eqFoo[A: Eq]: Eq[Foo[A]] = ??? + } + + type FooT[F[_], A] = F[Foo[A]] + object FooT { + def liftF[F[_], A](fa: F[A]): F[Foo[A]] = + map(fa)(???) // error + + def map[F[_], A, B](ffa: F[Foo[A]])(f: A => B): F[Foo[B]] = + ??? + } + + trait Order[A] extends Eq[A] + + trait Eq[A] + + object Eq { + implicit def catsKernelOrderForTuple14[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12], A13: Order[A13]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13)] = ??? + implicit def catsKernelOrderForTuple13[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11], A12: Order[A12]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12)] = ??? + implicit def catsKernelOrderForTuple12[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10], A11: Order[A11]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11)] = ??? + implicit def catsKernelOrderForTuple11[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9], A10: Order[A10]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)] = ??? + implicit def catsKernelOrderForTuple10[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8], A9: Order[A9]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9)] = ??? + implicit def catsKernelOrderForTuple9[A0, A1, A2, A3, A4, A5, A6, A7, A8](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7], A8: Order[A8]): Order[(A0, A1, A2, A3, A4, A5, A6, A7, A8)] = ??? + implicit def catsKernelOrderForTuple8[A0, A1, A2, A3, A4, A5, A6, A7](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6], A7: Order[A7]): Order[(A0, A1, A2, A3, A4, A5, A6, A7)] = ??? + implicit def catsKernelOrderForTuple7[A0, A1, A2, A3, A4, A5, A6](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5], A6: Order[A6]): Order[(A0, A1, A2, A3, A4, A5, A6)] = ??? + implicit def catsKernelOrderForTuple6[A0, A1, A2, A3, A4, A5](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4], A5: Order[A5]): Order[(A0, A1, A2, A3, A4, A5)] = ??? + implicit def catsKernelOrderForTuple5[A0, A1, A2, A3, A4](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3], A4: Order[A4]): Order[(A0, A1, A2, A3, A4)] = ??? + implicit def catsKernelOrderForTuple4[A0, A1, A2, A3](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2], A3: Order[A3]): Order[(A0, A1, A2, A3)] = ??? + implicit def catsKernelOrderForTuple3[A0, A1, A2](implicit A0: Order[A0], A1: Order[A1], A2: Order[A2]): Order[(A0, A1, A2)] = ??? + implicit def catsKernelOrderForTuple2[A0, A1](implicit A0: Order[A0], A1: Order[A1]): Order[(A0, A1)] = ??? + implicit def catsKernelOrderForTuple1[A0](implicit A0: Order[A0]): Order[Tuple1[A0]] = ??? + } + +} \ No newline at end of file diff --git a/tests/pos/i7745.scala b/tests/neg/i7745.scala similarity index 72% rename from tests/pos/i7745.scala rename to tests/neg/i7745.scala index de03d3995d33..7b54be159661 100644 --- a/tests/pos/i7745.scala +++ b/tests/neg/i7745.scala @@ -1,3 +1,3 @@ trait F[x] implicit def foo[f[_], y, x <: f[y]](implicit ev: F[y]): F[x] = ??? -val test = implicitly \ No newline at end of file +val test = implicitly // error \ No newline at end of file From 93dc3e261ce8830e30a8ee8cdb12a1bf4ccdb90c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 9 Nov 2021 17:24:40 +0100 Subject: [PATCH 0814/1244] Fix neg test --- tests/neg/i9330.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/neg/i9330.scala b/tests/neg/i9330.scala index 6ba57c033473..ca25582ef7e8 100644 --- a/tests/neg/i9330.scala +++ b/tests/neg/i9330.scala @@ -1,4 +1,4 @@ val x = { - () == "" + () == "" // error implicit def foo[A: A] // error // error // error } From 9c350135f9582cbccb7ca57533a4e367af38193a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 9 Nov 2021 18:13:24 +0100 Subject: [PATCH 0815/1244] Revive original test Make another test to exercise the original large search behavior --- .../dotty/tools/dotc/CompilationTests.scala | 1 + tests/neg-custom-args/i13838.check | 26 +++++++++++++++++++ tests/{neg => neg-custom-args}/i13838.scala | 4 ++- 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/neg-custom-args/i13838.check rename tests/{neg => neg-custom-args}/i13838.scala (99%) diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index a9f376d3cda6..06526aa6a924 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -183,6 +183,7 @@ class CompilationTests { compileFile("tests/neg-custom-args/feature-shadowing.scala", defaultOptions.and("-Xfatal-warnings", "-feature")), compileDir("tests/neg-custom-args/hidden-type-errors", defaultOptions.and("-explain")), compileFile("tests/neg-custom-args/i13026.scala", defaultOptions.and("-print-lines")), + compileFile("tests/neg-custom-args/i13838.scala", defaultOptions.and("-Ximplicit-search-limit", "1000")), ).checkExpectedErrors() } diff --git a/tests/neg-custom-args/i13838.check b/tests/neg-custom-args/i13838.check new file mode 100644 index 000000000000..5730cb144e52 --- /dev/null +++ b/tests/neg-custom-args/i13838.check @@ -0,0 +1,26 @@ +-- Error: tests/neg-custom-args/i13838.scala:10:5 ---------------------------------------------------------------------- +10 | foo // error + | ^ + |no implicit argument of type Order[X] was found for parameter x$1 of method foo in object FooT + | + |where: X is a type variable + |. + |I found: + | + | FooT.OrderFFooA[F, A](FooT.OrderFFooA[F, A](/* missing */summon[Order[F[Foo[A]]]])) + | + |But given instance OrderFFooA in object FooT produces a diverging implicit search when trying to match type Order[F[Foo[A]]]. +-- [E168] Type Warning: tests/neg-custom-args/i13838.scala:10:5 -------------------------------------------------------- +10 | foo // error + | ^ + | Implicit search problem too large. + | an implicit search was terminated with failure after trying 1000 expressions. + | The root candidate for the search was: + | + | given instance OrderFFooA in object FooT for Order[Any]} + | + | You can change the behavior by setting the `-Ximplicit-search-limit` value. + | Smaller values cause the search to fail faster. + | Larger values might make a very large search problem succeed. + +longer explanation available when compiling with `-explain` diff --git a/tests/neg/i13838.scala b/tests/neg-custom-args/i13838.scala similarity index 99% rename from tests/neg/i13838.scala rename to tests/neg-custom-args/i13838.scala index 92e7a6d48439..c99d3fa1f82d 100644 --- a/tests/neg/i13838.scala +++ b/tests/neg-custom-args/i13838.scala @@ -5,7 +5,9 @@ object Foo: given [A: Eq]: Eq[Foo[A]] = ??? object FooT: - def liftF[F[_], A](fa: F[A]): F[Foo[A]] = map(fa)(???) // error + + def foo[X](using Order[X]): Unit = ??? + foo // error def map[F[_], A](ffa: F[Foo[A]])(f: A): Nothing = ??? From 664d211e0a914e6d530c4a65492441e47731f049 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 12 Oct 2021 09:25:52 +0200 Subject: [PATCH 0816/1244] Name mangle methods with erased context results Add a `$` to the name of a method that has erased context results and that may override some other method. This is to prevent the two methods from having the same names and parameters in their erased signatures. We need a bridge between the two methods, so they are not allowed to already override after erasure. --- .../dotty/tools/dotc/core/Definitions.scala | 28 +++---------------- .../dotty/tools/dotc/core/TypeErasure.scala | 4 +-- .../transform/ContextFunctionResults.scala | 13 +++++++++ .../dotty/tools/dotc/transform/Erasure.scala | 18 +++++++++--- .../dotc/transform/GenericSignatures.scala | 4 +-- 5 files changed, 35 insertions(+), 32 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 60f375c116fc..7f2ec75af8df 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -1353,39 +1353,19 @@ class Definitions { def isBoxedUnitClass(cls: Symbol): Boolean = cls.isClass && (cls.owner eq ScalaRuntimePackageClass) && cls.name == tpnme.BoxedUnit - /** Returns the erased class of the function class `cls` - * - FunctionN for N > 22 becomes FunctionXXL - * - FunctionN for 22 > N >= 0 remains as FunctionN - * - ContextFunctionN for N > 22 becomes FunctionXXL - * - ContextFunctionN for N <= 22 becomes FunctionN - * - ErasedFunctionN becomes Function0 - * - ImplicitErasedFunctionN becomes Function0 - * - anything else becomes a NoSymbol - */ - def erasedFunctionClass(cls: Symbol): Symbol = { - val arity = scalaClassName(cls).functionArity - if (cls.name.isErasedFunction) FunctionClass(0) - else if (arity > 22) FunctionXXLClass - else if (arity >= 0) FunctionClass(arity) - else NoSymbol - } - /** Returns the erased type of the function class `cls` * - FunctionN for N > 22 becomes FunctionXXL * - FunctionN for 22 > N >= 0 remains as FunctionN * - ContextFunctionN for N > 22 becomes FunctionXXL * - ContextFunctionN for N <= 22 becomes FunctionN - * - ErasedFunctionN becomes Function0 - * - ImplicitErasedFunctionN becomes Function0 * - anything else becomes a NoType */ - def erasedFunctionType(cls: Symbol): Type = { + def functionTypeErasure(cls: Symbol): Type = val arity = scalaClassName(cls).functionArity - if (cls.name.isErasedFunction) FunctionType(0) - else if (arity > 22) FunctionXXLClass.typeRef - else if (arity >= 0) FunctionType(arity) + if cls.name.isErasedFunction then FunctionType(0) + else if arity > 22 then FunctionXXLClass.typeRef + else if arity >= 0 then FunctionType(arity) else NoType - } val predefClassNames: Set[Name] = Set("Predef$", "DeprecatedPredef", "LowPriorityImplicits").map(_.toTypeName.unmangleClassName) diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 7e89b4e2c2c9..6435d0622ebd 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -581,7 +581,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst val sym = tp.symbol if (!sym.isClass) this(tp.translucentSuperType) else if (semiEraseVCs && isDerivedValueClass(sym)) eraseDerivedValueClass(tp) - else if (defn.isSyntheticFunctionClass(sym)) defn.erasedFunctionType(sym) + else if (defn.isSyntheticFunctionClass(sym)) defn.functionTypeErasure(sym) else eraseNormalClassRef(tp) case tp: AppliedType => val tycon = tp.tycon @@ -791,7 +791,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst if (erasedVCRef.exists) return sigName(erasedVCRef) } if (defn.isSyntheticFunctionClass(sym)) - sigName(defn.erasedFunctionType(sym)) + sigName(defn.functionTypeErasure(sym)) else val cls = normalizeClass(sym.asClass) val fullName = diff --git a/compiler/src/dotty/tools/dotc/transform/ContextFunctionResults.scala b/compiler/src/dotty/tools/dotc/transform/ContextFunctionResults.scala index ee56767054fd..4247b835f640 100644 --- a/compiler/src/dotty/tools/dotc/transform/ContextFunctionResults.scala +++ b/compiler/src/dotty/tools/dotc/transform/ContextFunctionResults.scala @@ -8,12 +8,16 @@ import StdNames.nme import ast.untpd import ast.tpd._ import config.Config +import Decorators.* object ContextFunctionResults: /** Annotate methods that have context function result types directly matched by context * closures on their right-hand side. Parameters to such closures will be integrated * as additional method parameters in erasure. + * + * A @ContextResultCount(n) annotation means that the method's result type + * consists of a string of `n` nested context closures. */ def annotateContextResults(mdef: DefDef)(using Context): Unit = def contextResultCount(rhs: Tree, tp: Type): Int = tp match @@ -50,6 +54,15 @@ object ContextFunctionResults: crCount case none => 0 + /** True iff `ContextResultCount` is not zero and all context functions in the result + * type are erased. + */ + def contextResultsAreErased(sym: Symbol)(using Context): Boolean = + def allErased(tp: Type): Boolean = tp.dealias match + case defn.ContextFunctionType(_, resTpe, isErased) => isErased && allErased(resTpe) + case _ => true + contextResultCount(sym) > 0 && allErased(sym.info.finalResultType) + /** Turn the first `crCount` context function types in the result type of `tp` * into the curried method types. */ diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index ae2eac2c20fd..79bc47ced3f1 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -12,7 +12,7 @@ import core.Types._ import core.Names._ import core.StdNames._ import core.NameOps._ -import core.NameKinds.{AdaptedClosureName, BodyRetainerName} +import core.NameKinds.{AdaptedClosureName, BodyRetainerName, ImplMethName} import core.Scopes.newScopeWith import core.Decorators._ import core.Constants._ @@ -57,6 +57,17 @@ class Erasure extends Phase with DenotTransformer { case _ => false } } + def erasedName = + if ref.is(Flags.Method) + && contextResultsAreErased(ref.symbol) + && (ref.owner.is(Flags.Trait) || ref.symbol.allOverriddenSymbols.hasNext) + then + // Add a `$` to prevent this method from having the same signature + // as a method it overrides. We need a bridge between the + // two methods, so they are not allowed to already override after erasure. + ImplMethName(ref.targetName.asTermName) + else + ref.targetName assert(ctx.phase == this, s"transforming $ref at ${ctx.phase}") if (ref.symbol eq defn.ObjectClass) { @@ -80,7 +91,7 @@ class Erasure extends Phase with DenotTransformer { val oldOwner = ref.owner val newOwner = if oldOwner == defn.AnyClass then defn.ObjectClass else oldOwner val oldName = ref.name - val newName = ref.targetName + val newName = erasedName val oldInfo = ref.info var newInfo = transformInfo(oldSymbol, oldInfo) val oldFlags = ref.flags @@ -392,7 +403,6 @@ object Erasure { cast(tree, pt) end adaptToType - /** The following code: * * val f: Function1[Int, Any] = x => ... @@ -720,7 +730,7 @@ object Erasure { assert(sym.isConstructor, s"${sym.showLocated}") defn.specialErasure(owner) else if defn.isSyntheticFunctionClass(owner) then - defn.erasedFunctionClass(owner) + defn.functionTypeErasure(owner).typeSymbol else owner diff --git a/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala b/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala index c12c5c8b4a6e..18b028d1a024 100644 --- a/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala +++ b/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala @@ -274,10 +274,10 @@ object GenericSignatures { jsig(erasedUnderlying, toplevel, primitiveOK) } else if (defn.isSyntheticFunctionClass(sym)) { - val erasedSym = defn.erasedFunctionClass(sym) + val erasedSym = defn.functionTypeErasure(sym).typeSymbol classSig(erasedSym, pre, if (erasedSym.typeParams.isEmpty) Nil else args) } - else if (sym.isClass) + else if sym.isClass then classSig(sym, pre, args) else jsig(erasure(tp), toplevel, primitiveOK) From ed05f81391b2694526f1a959aa6801077355360f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 13 Oct 2021 09:58:44 +0200 Subject: [PATCH 0817/1244] Fix eta expand at erasure to take erased CFTs into account --- compiler/src/dotty/tools/dotc/ast/tpd.scala | 19 +++++- .../src/dotty/tools/dotc/core/Symbols.scala | 4 ++ .../tools/dotc/transform/AccessProxies.scala | 5 +- .../dotty/tools/dotc/transform/Bridges.scala | 53 ++++++++++++++-- .../tools/dotc/transform/ByNameClosures.scala | 6 +- .../transform/ContextFunctionResults.scala | 34 +++-------- .../dotty/tools/dotc/transform/Erasure.scala | 60 +------------------ .../dotty/tools/dotc/typer/Synthesizer.scala | 2 +- .../quoted/runtime/impl/QuoteMatcher.scala | 2 +- .../quoted/runtime/impl/QuotesImpl.scala | 4 +- tests/run/i13691.scala | 53 ++++++++++++++++ tests/run/i13961a.scala | 11 ++++ 12 files changed, 154 insertions(+), 99 deletions(-) create mode 100644 tests/run/i13691.scala create mode 100644 tests/run/i13961a.scala diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 0c12eff2a0ae..2db0bd6de2d4 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -121,9 +121,9 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { Closure(Nil, call, targetTpt)) } - /** A closure whole anonymous function has the given method type */ + /** A closure whose anonymous function has the given method type */ def Lambda(tpe: MethodType, rhsFn: List[Tree] => Tree)(using Context): Block = { - val meth = newSymbol(ctx.owner, nme.ANON_FUN, Synthetic | Method, tpe) + val meth = newAnonFun(ctx.owner, tpe) Closure(meth, tss => rhsFn(tss.head).changeOwner(ctx.owner, meth)) } @@ -1104,6 +1104,21 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { if (sym.exists) sym.defTree = tree tree } + + def etaExpandCFT(using Context): Tree = + def expand(target: Tree, tp: Type)(using Context): Tree = tp match + case defn.ContextFunctionType(argTypes, resType, isErased) => + val anonFun = newAnonFun( + ctx.owner, + MethodType.companion(isContextual = true, isErased = isErased)(argTypes, resType), + coord = ctx.owner.coord) + def lambdaBody(refss: List[List[Tree]]) = + expand(target.select(nme.apply).appliedToArgss(refss), resType)( + using ctx.withOwner(anonFun)) + Closure(anonFun, lambdaBody) + case _ => + target + expand(tree, tree.tpe.widen) } inline val MapRecursionLimit = 10 diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 9e4730534bf7..e49399ff9791 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -712,6 +712,10 @@ object Symbols { coord: Coord = NoCoord)(using Context): TermSymbol = newSymbol(cls, nme.CONSTRUCTOR, flags | Method, MethodType(paramNames, paramTypes, cls.typeRef), privateWithin, coord) + /** Create an anonymous function symbol */ + def newAnonFun(owner: Symbol, info: Type, coord: Coord = NoCoord)(using Context): TermSymbol = + newSymbol(owner, nme.ANON_FUN, Synthetic | Method, info, coord = coord) + /** Create an empty default constructor symbol for given class `cls`. */ def newDefaultConstructor(cls: ClassSymbol)(using Context): TermSymbol = newConstructor(cls, EmptyFlags, Nil, Nil) diff --git a/compiler/src/dotty/tools/dotc/transform/AccessProxies.scala b/compiler/src/dotty/tools/dotc/transform/AccessProxies.scala index 81d029e023fb..de25cb140da0 100644 --- a/compiler/src/dotty/tools/dotc/transform/AccessProxies.scala +++ b/compiler/src/dotty/tools/dotc/transform/AccessProxies.scala @@ -51,7 +51,10 @@ abstract class AccessProxies { forwardedArgss.nonEmpty && forwardedArgss.head.nonEmpty) // defensive conditions accessRef.becomes(forwardedArgss.head.head) else - accessRef.appliedToTypeTrees(forwardedTpts).appliedToArgss(forwardedArgss) + accessRef + .appliedToTypeTrees(forwardedTpts) + .appliedToArgss(forwardedArgss) + .etaExpandCFT(using ctx.withOwner(accessor)) rhs.withSpan(accessed.span) }) diff --git a/compiler/src/dotty/tools/dotc/transform/Bridges.scala b/compiler/src/dotty/tools/dotc/transform/Bridges.scala index d91840f247b6..f7c00ef74b94 100644 --- a/compiler/src/dotty/tools/dotc/transform/Bridges.scala +++ b/compiler/src/dotty/tools/dotc/transform/Bridges.scala @@ -9,6 +9,11 @@ import ast.untpd import collection.{mutable, immutable} import util.Spans.Span import util.SrcPos +import ContextFunctionResults.{contextResultCount, contextFunctionResultTypeAfter} +import StdNames.nme +import Constants.Constant +import TypeErasure.transformInfo +import Erasure.Boxing.adaptClosure /** A helper class for generating bridge methods in class `root`. */ class Bridges(root: ClassSymbol, thisPhase: DenotTransformer)(using Context) { @@ -112,12 +117,52 @@ class Bridges(root: ClassSymbol, thisPhase: DenotTransformer)(using Context) { toBeRemoved += other } - def bridgeRhs(argss: List[List[Tree]]) = { + val memberCount = contextResultCount(member) + + /** Eta expand application `ref(args)` as needed. + * To do this correctly, we have to look at the member's original pre-erasure + * type and figure out which context function types in its result are + * not yet instantiated. + */ + def etaExpand(ref: Tree, args: List[Tree])(using Context): Tree = + def expand(args: List[Tree], tp: Type, n: Int)(using Context): Tree = + if n <= 0 then + assert(ctx.typer.isInstanceOf[Erasure.Typer]) + ctx.typer.typed(untpd.cpy.Apply(ref)(ref, args), member.info.finalResultType) + else + val defn.ContextFunctionType(argTypes, resType, isErased) = tp: @unchecked + val anonFun = newAnonFun(ctx.owner, + MethodType(if isErased then Nil else argTypes, resType), + coord = ctx.owner.coord) + anonFun.info = transformInfo(anonFun, anonFun.info) + + def lambdaBody(refss: List[List[Tree]]) = + val refs :: Nil = refss: @unchecked + val expandedRefs = refs.map(_.withSpan(ctx.owner.span.endPos)) match + case (bunchedParam @ Ident(nme.ALLARGS)) :: Nil => + argTypes.indices.toList.map(n => + bunchedParam + .select(nme.primitive.arrayApply) + .appliedTo(Literal(Constant(n)))) + case refs1 => refs1 + expand(args ::: expandedRefs, resType, n - 1)(using ctx.withOwner(anonFun)) + + val unadapted = Closure(anonFun, lambdaBody) + cpy.Block(unadapted)(unadapted.stats, + adaptClosure(unadapted.expr.asInstanceOf[Closure])) + end expand + + val otherCount = contextResultCount(other) + val start = contextFunctionResultTypeAfter(member, otherCount)(using preErasureCtx) + expand(args, start, memberCount - otherCount)(using ctx.withOwner(bridge)) + end etaExpand + + def bridgeRhs(argss: List[List[Tree]]) = assert(argss.tail.isEmpty) val ref = This(root).select(member) - if (member.info.isParameterless) ref // can happen if `member` is a module - else Erasure.partialApply(ref, argss.head) - } + if member.info.isParameterless then ref // can happen if `member` is a module + else if memberCount == 0 then ref.appliedToTermArgs(argss.head) + else etaExpand(ref, argss.head) bridges += DefDef(bridge, bridgeRhs(_).withSpan(bridge.span)) } diff --git a/compiler/src/dotty/tools/dotc/transform/ByNameClosures.scala b/compiler/src/dotty/tools/dotc/transform/ByNameClosures.scala index 00bcd1e5076a..51242e7f2dbe 100644 --- a/compiler/src/dotty/tools/dotc/transform/ByNameClosures.scala +++ b/compiler/src/dotty/tools/dotc/transform/ByNameClosures.scala @@ -30,11 +30,9 @@ class ByNameClosures extends TransformByNameApply with IdentityDenotTransformer // ExpanSAMs applied to partial functions creates methods that need // to be fully defined before converting. Test case is pos/i9391.scala. - override def mkByNameClosure(arg: Tree, argType: Type)(using Context): Tree = { - val meth = newSymbol( - ctx.owner, nme.ANON_FUN, Synthetic | Method, MethodType(Nil, Nil, argType)) + override def mkByNameClosure(arg: Tree, argType: Type)(using Context): Tree = + val meth = newAnonFun(ctx.owner, MethodType(Nil, argType)) Closure(meth, _ => arg.changeOwnerAfter(ctx.owner, meth, thisPhase)).withSpan(arg.span) - } } object ByNameClosures { diff --git a/compiler/src/dotty/tools/dotc/transform/ContextFunctionResults.scala b/compiler/src/dotty/tools/dotc/transform/ContextFunctionResults.scala index 4247b835f640..14134b4bb1fa 100644 --- a/compiler/src/dotty/tools/dotc/transform/ContextFunctionResults.scala +++ b/compiler/src/dotty/tools/dotc/transform/ContextFunctionResults.scala @@ -99,33 +99,13 @@ object ContextFunctionResults: normalParamCount(sym.info) end totalParamCount - /** The rightmost context function type in the result type of `meth` - * that represents `paramCount` curried, non-erased parameters that - * are included in the `contextResultCount` of `meth`. - * Example: - * - * Say we have `def m(x: A): B ?=> (C1, C2, C3) ?=> D ?=> E ?=> F`, - * paramCount == 4, and the contextResultCount of `m` is 3. - * Then we return the type `(C1, C2, C3) ?=> D ?=> E ?=> F`, since this - * type covers the 4 rightmost parameters C1, C2, C3 and D before the - * contextResultCount runs out at E ?=> F. - * Erased parameters are ignored; they contribute nothing to the - * parameter count. - */ - def contextFunctionResultTypeCovering(meth: Symbol, paramCount: Int)(using Context) = - atPhase(erasurePhase) { - // Recursive instances return pairs of context types and the - // # of parameters they represent. - def missingCR(tp: Type, crCount: Int): (Type, Int) = - if crCount == 0 then (tp, 0) - else - val defn.ContextFunctionType(formals, resTpe, isErased) = tp: @unchecked - val result @ (rt, nparams) = missingCR(resTpe, crCount - 1) - assert(nparams <= paramCount) - if nparams == paramCount || isErased then result - else (tp, nparams + formals.length) - missingCR(meth.info.finalResultType, contextResultCount(meth))._1 - } + /** The `depth` levels nested context function type in the result type of `meth` */ + def contextFunctionResultTypeAfter(meth: Symbol, depth: Int)(using Context) = + def recur(tp: Type, n: Int): Type = + if n == 0 then tp + else tp match + case defn.ContextFunctionType(_, resTpe, _) => recur(resTpe, n - 1) + recur(meth.info.finalResultType, depth) /** Should selection `tree` be eliminated since it refers to an `apply` * node of a context function type whose parameters will end up being diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index 79bc47ced3f1..48064d9dc280 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -57,6 +57,7 @@ class Erasure extends Phase with DenotTransformer { case _ => false } } + def erasedName = if ref.is(Flags.Method) && contextResultsAreErased(ref.symbol) @@ -383,8 +384,8 @@ object Erasure { case _: FunProto | AnyFunctionProto => tree case _ => tree.tpe.widen match case mt: MethodType if tree.isTerm => - if mt.paramInfos.isEmpty then adaptToType(tree.appliedToNone, pt) - else etaExpand(tree, mt, pt) + assert(mt.paramInfos.isEmpty) + adaptToType(tree.appliedToNone, pt) case tpw => if (pt.isInstanceOf[ProtoType] || tree.tpe <:< pt) tree @@ -533,61 +534,6 @@ object Erasure { else tree end adaptClosure - - /** Eta expand given `tree` that has the given method type `mt`, so that - * it conforms to erased result type `pt`. - * To do this correctly, we have to look at the tree's original pre-erasure - * type and figure out which context function types in its result are - * not yet instantiated. - */ - def etaExpand(tree: Tree, mt: MethodType, pt: Type)(using Context): Tree = - report.log(i"eta expanding $tree") - val defs = new mutable.ListBuffer[Tree] - val tree1 = LiftErased.liftApp(defs, tree) - val xmt = if tree.isInstanceOf[Apply] then mt else expandedMethodType(mt, tree) - val targetLength = xmt.paramInfos.length - val origOwner = ctx.owner - - // The original type from which closures should be constructed - val origType = contextFunctionResultTypeCovering(tree.symbol, targetLength) - - def abstracted(args: List[Tree], tp: Type, pt: Type)(using Context): Tree = - if args.length < targetLength then - try - val defn.ContextFunctionType(argTpes, resTpe, isErased) = tp: @unchecked - if isErased then abstracted(args, resTpe, pt) - else - val anonFun = newSymbol( - ctx.owner, nme.ANON_FUN, Flags.Synthetic | Flags.Method, - MethodType(argTpes, resTpe), coord = tree.span.endPos) - anonFun.info = transformInfo(anonFun, anonFun.info) - def lambdaBody(refss: List[List[Tree]]) = - val refs :: Nil = refss: @unchecked - val expandedRefs = refs.map(_.withSpan(tree.span.endPos)) match - case (bunchedParam @ Ident(nme.ALLARGS)) :: Nil => - argTpes.indices.toList.map(n => - bunchedParam - .select(nme.primitive.arrayApply) - .appliedTo(Literal(Constant(n)))) - case refs1 => refs1 - abstracted(args ::: expandedRefs, resTpe, anonFun.info.finalResultType)( - using ctx.withOwner(anonFun)) - - val unadapted = Closure(anonFun, lambdaBody) - cpy.Block(unadapted)(unadapted.stats, adaptClosure(unadapted.expr.asInstanceOf[Closure])) - catch case ex: MatchError => - println(i"error while abstracting tree = $tree | mt = $mt | args = $args%, % | tp = $tp | pt = $pt") - throw ex - else - assert(args.length == targetLength, i"wrong # args tree = $tree | args = $args%, % | mt = $mt | tree type = ${tree.tpe}") - val app = untpd.cpy.Apply(tree1)(tree1, args) - assert(ctx.typer.isInstanceOf[Erasure.Typer]) - ctx.typer.typed(app, pt) - .changeOwnerAfter(origOwner, ctx.owner, erasurePhase.asInstanceOf[Erasure]) - - seq(defs.toList, abstracted(Nil, origType, pt)) - end etaExpand - end Boxing class Typer(erasurePhase: DenotTransformer) extends typer.ReTyper with NoChecking { diff --git a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala index 2dd088d70671..44351b9a213c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala @@ -70,7 +70,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context): ref(defn.NoneModule)) } val tpe = MethodType(List(nme.s))(_ => List(tp1), mth => defn.OptionClass.typeRef.appliedTo(mth.newParamRef(0) & tp2)) - val meth = newSymbol(ctx.owner, nme.ANON_FUN, Synthetic | Method, tpe, coord = span) + val meth = newAnonFun(ctx.owner, tpe, coord = span) val typeTestType = defn.TypeTestClass.typeRef.appliedTo(List(tp1, tp2)) Closure(meth, tss => body(tss.head).changeOwner(ctx.owner, meth), targetType = typeTestType).withSpan(span) case _ => diff --git a/compiler/src/scala/quoted/runtime/impl/QuoteMatcher.scala b/compiler/src/scala/quoted/runtime/impl/QuoteMatcher.scala index 1ee0d9d34dfa..6d9ff6ca68a8 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuoteMatcher.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuoteMatcher.scala @@ -212,7 +212,7 @@ object QuoteMatcher { } val argTypes = args.map(x => x.tpe.widenTermRefExpr) val methTpe = MethodType(names)(_ => argTypes, _ => pattern.tpe) - val meth = newSymbol(ctx.owner, nme.ANON_FUN, Synthetic | Method, methTpe) + val meth = newAnonFun(ctx.owner, methTpe) def bodyFn(lambdaArgss: List[List[Tree]]): Tree = { val argsMap = args.map(_.symbol).zip(lambdaArgss.head).toMap val body = new TreeMap { diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index 1510640cfce6..d6e13fbbd168 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -385,7 +385,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler case t => t } val closureTpe = Types.MethodType(mtpe.paramNames, mtpe.paramInfos, closureResType) - val closureMethod = dotc.core.Symbols.newSymbol(owner, nme.ANON_FUN, Synthetic | Method, closureTpe) + val closureMethod = dotc.core.Symbols.newAnonFun(owner, closureTpe) tpd.Closure(closureMethod, tss => new tpd.TreeOps(self).appliedToTermArgs(tss.head).etaExpand(closureMethod)) case _ => self } @@ -793,7 +793,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler object Lambda extends LambdaModule: def apply(owner: Symbol, tpe: MethodType, rhsFn: (Symbol, List[Tree]) => Tree): Block = - val meth = dotc.core.Symbols.newSymbol(owner, nme.ANON_FUN, Synthetic | Method, tpe) + val meth = dotc.core.Symbols.newAnonFun(owner, tpe) withDefaultPos(tpd.Closure(meth, tss => xCheckMacroedOwners(xCheckMacroValidExpr(rhsFn(meth, tss.head.map(withDefaultPos))), meth))) def unapply(tree: Block): Option[(List[ValDef], Term)] = tree match { diff --git a/tests/run/i13691.scala b/tests/run/i13691.scala new file mode 100644 index 000000000000..6db01ee0de35 --- /dev/null +++ b/tests/run/i13691.scala @@ -0,0 +1,53 @@ +import language.experimental.erasedDefinitions + +erased class CanThrow[-E <: Exception] +erased class Foo +class Bar + +object unsafeExceptions: + given canThrowAny: CanThrow[Exception] = null + +object test1: + trait Decoder[+T]: + def apply(): T + + def deco: Decoder[CanThrow[Exception] ?=> Int] = new Decoder[CanThrow[Exception] ?=> Int]: + def apply(): CanThrow[Exception] ?=> Int = 1 + +object test2: + trait Decoder[+T]: + def apply(): T + + def deco: Decoder[(CanThrow[Exception], Foo) ?=> Int] = new Decoder[(CanThrow[Exception], Foo) ?=> Int]: + def apply(): (CanThrow[Exception], Foo) ?=> Int = 1 + +object test3: + trait Decoder[+T]: + def apply(): T + + def deco: Decoder[CanThrow[Exception] ?=> Foo ?=> Int] = new Decoder[CanThrow[Exception] ?=> Foo ?=> Int]: + def apply(): CanThrow[Exception] ?=> Foo ?=> Int = 1 + +object test4: + trait Decoder[+T]: + def apply(): T + + def deco: Decoder[CanThrow[Exception] ?=> Bar ?=> Int] = new Decoder[CanThrow[Exception] ?=> Bar ?=> Int]: + def apply(): CanThrow[Exception] ?=> Bar ?=> Int = 1 + +object test5: + trait Decoder[+T]: + def apply(): T + + def deco: Decoder[Bar ?=> CanThrow[Exception] ?=> Int] = new Decoder[Bar ?=> CanThrow[Exception] ?=> Int]: + def apply(): Bar ?=> CanThrow[Exception] ?=> Int = 1 + +@main def Test(): Unit = + import unsafeExceptions.canThrowAny + given Foo = ??? + given Bar = Bar() + test1.deco.apply().apply + test2.deco.apply().apply + test3.deco.apply().apply + test4.deco.apply().apply + test5.deco.apply().apply diff --git a/tests/run/i13961a.scala b/tests/run/i13961a.scala new file mode 100644 index 000000000000..9d49ab30b0a4 --- /dev/null +++ b/tests/run/i13961a.scala @@ -0,0 +1,11 @@ +import language.experimental.saferExceptions + +trait Decoder[+T]: + def apply(): T + +given Decoder[Int throws Exception] = new Decoder[Int throws Exception]: + def apply(): Int throws Exception = 1 + +@main def Test(): Unit = + import unsafeExceptions.canThrowAny + summon[Decoder[Int throws Exception]]() \ No newline at end of file From 305a6a65e0fa3644c9a970acbf1d45845733dbf4 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 3 Nov 2021 10:24:52 +0100 Subject: [PATCH 0818/1244] Bring back deleted doc comment --- compiler/src/dotty/tools/dotc/core/Definitions.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 7f2ec75af8df..16ce0e381c75 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -1358,6 +1358,8 @@ class Definitions { * - FunctionN for 22 > N >= 0 remains as FunctionN * - ContextFunctionN for N > 22 becomes FunctionXXL * - ContextFunctionN for N <= 22 becomes FunctionN + * - ErasedFunctionN becomes Function0 + * - ImplicitErasedFunctionN becomes Function0 * - anything else becomes a NoType */ def functionTypeErasure(cls: Symbol): Type = From 7f17c55228dc635f9e211f771f80941d18f8b4d0 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 3 Nov 2021 10:43:47 +0100 Subject: [PATCH 0819/1244] Use "$direct" instead of just "$" to prevent erasure clashes Use "$direct" instead of just "$" to prevent erasure clashes of methods with erased context function results. --- compiler/src/dotty/tools/dotc/core/NameKinds.scala | 2 +- compiler/src/dotty/tools/dotc/core/NameTags.scala | 7 ++++--- compiler/src/dotty/tools/dotc/transform/Erasure.scala | 6 +++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameKinds.scala b/compiler/src/dotty/tools/dotc/core/NameKinds.scala index e17e772de993..b77f870b72b7 100644 --- a/compiler/src/dotty/tools/dotc/core/NameKinds.scala +++ b/compiler/src/dotty/tools/dotc/core/NameKinds.scala @@ -365,7 +365,7 @@ object NameKinds { val ExtMethName: SuffixNameKind = new SuffixNameKind(EXTMETH, "$extension") val ParamAccessorName: SuffixNameKind = new SuffixNameKind(PARAMACC, "$accessor") val ModuleClassName: SuffixNameKind = new SuffixNameKind(OBJECTCLASS, "$", optInfoString = "ModuleClass") - val ImplMethName: SuffixNameKind = new SuffixNameKind(IMPLMETH, "$") + val DirectMethName: SuffixNameKind = new SuffixNameKind(DIRECT, "$direct") val AdaptedClosureName: SuffixNameKind = new SuffixNameKind(ADAPTEDCLOSURE, "$adapted") { override def definesNewName = true } val SyntheticSetterName: SuffixNameKind = new SuffixNameKind(SETTER, "_$eq") diff --git a/compiler/src/dotty/tools/dotc/core/NameTags.scala b/compiler/src/dotty/tools/dotc/core/NameTags.scala index 63aea8853235..67dfcec73c53 100644 --- a/compiler/src/dotty/tools/dotc/core/NameTags.scala +++ b/compiler/src/dotty/tools/dotc/core/NameTags.scala @@ -24,8 +24,9 @@ object NameTags extends TastyFormat.NameTags { final val ADAPTEDCLOSURE = 31 // Used in Erasure to adapt closures over primitive types. - final val IMPLMETH = 32 // Used to define methods in implementation classes - // (can probably be removed). + final val DIRECT = 32 // Used to define implementations of methods with + // erased context function results that can override some + // other method. final val PARAMACC = 33 // Used for a private parameter alias @@ -48,7 +49,7 @@ object NameTags extends TastyFormat.NameTags { case INITIALIZER => "INITIALIZER" case FIELD => "FIELD" case EXTMETH => "EXTMETH" - case IMPLMETH => "IMPLMETH" + case DIRECT => "DIRECT" case PARAMACC => "PARAMACC" case ADAPTEDCLOSURE => "ADAPTEDCLOSURE" case OBJECTCLASS => "OBJECTCLASS" diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index 48064d9dc280..ab6f00dfc575 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -12,7 +12,7 @@ import core.Types._ import core.Names._ import core.StdNames._ import core.NameOps._ -import core.NameKinds.{AdaptedClosureName, BodyRetainerName, ImplMethName} +import core.NameKinds.{AdaptedClosureName, BodyRetainerName, DirectMethName} import core.Scopes.newScopeWith import core.Decorators._ import core.Constants._ @@ -63,10 +63,10 @@ class Erasure extends Phase with DenotTransformer { && contextResultsAreErased(ref.symbol) && (ref.owner.is(Flags.Trait) || ref.symbol.allOverriddenSymbols.hasNext) then - // Add a `$` to prevent this method from having the same signature + // Add a `$direct` to prevent this method from having the same signature // as a method it overrides. We need a bridge between the // two methods, so they are not allowed to already override after erasure. - ImplMethName(ref.targetName.asTermName) + DirectMethName(ref.targetName.asTermName) else ref.targetName From 01b5b4b9ba5d837b254550d0057ef869b8eaa349 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Mon, 8 Nov 2021 11:26:33 +0000 Subject: [PATCH 0820/1244] Fix messages leaking via suspended messages It isn't clear what StoreReporter's purpose is. Is it simply a store of all messages, or is it a store of "real" messages, i.e. messages that aren't suppressed with `@nowarn` or -Wconf (i.e. configurable warnings)? I believe StoreReporter is often used as a way to get programmatic access to the real messages. Typer, with its TyperState, uses StoreReporter as a more general buffer while making typing attempts, such as when trying to apply an implicit conversion. But with configurable warnings, we don't know if a warning is real or not until we've typed all the `@nowarn` annotation in the code, which is why we suspend the messages, on Run. So we add an override for TyperState, so that StoreReporter is used as simply a buffer. When it then unbuffers its messages in flush to the parent context's reporter, it will run through the regular "issueIfNotSuppressed" code (assuming it's not another store reporter). --- .../dotty/tools/dotc/core/TyperState.scala | 2 +- .../dotc/reporting/ExploringReporter.scala | 2 +- .../dotty/tools/dotc/reporting/Reporter.scala | 68 ++++++++++--------- .../tools/dotc/reporting/StoreReporter.scala | 9 ++- .../tools/dotc/reporting/TestReporter.scala | 2 +- 5 files changed, 46 insertions(+), 37 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TyperState.scala b/compiler/src/dotty/tools/dotc/core/TyperState.scala index 9aa51a6714c3..6163eebfbef4 100644 --- a/compiler/src/dotty/tools/dotc/core/TyperState.scala +++ b/compiler/src/dotty/tools/dotc/core/TyperState.scala @@ -103,7 +103,7 @@ class TyperState() { this /** A fresh typer state with the same constraint as this one. */ - def fresh(reporter: Reporter = StoreReporter(this.reporter), + def fresh(reporter: Reporter = StoreReporter(this.reporter, fromTyperState = true), committable: Boolean = this.isCommittable): TyperState = util.Stats.record("TyperState.fresh") TyperState().init(this, this.constraint) diff --git a/compiler/src/dotty/tools/dotc/reporting/ExploringReporter.scala b/compiler/src/dotty/tools/dotc/reporting/ExploringReporter.scala index e7b636cddf02..9255820140d8 100644 --- a/compiler/src/dotty/tools/dotc/reporting/ExploringReporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/ExploringReporter.scala @@ -7,7 +7,7 @@ import core.Contexts.Context import Diagnostic._ /** A re-usable Reporter used in Contexts#test */ -class ExploringReporter extends StoreReporter(null): +class ExploringReporter extends StoreReporter(null, fromTyperState = false): infos = new mutable.ListBuffer[Diagnostic] override def hasUnreportedErrors: Boolean = diff --git a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala index 8c736993de8e..e159b5f83863 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala @@ -137,42 +137,44 @@ abstract class Reporter extends interfaces.ReporterResult { var unreportedWarnings: Map[String, Int] = Map.empty + /** Issue the diagnostic, ignoring `-Wconf` and `@nowarn` configurations, + * but still honouring `-nowarn`, `-Werror`, and conditional warnings. */ + def issueUnconfigured(dia: Diagnostic)(using Context): Unit = dia match + case w: Warning if ctx.settings.silentWarnings.value => + case w: ConditionalWarning if w.isSummarizedConditional => + val key = w.enablingOption.name + val count = unreportedWarnings.getOrElse(key, 0) + unreportedWarnings = unreportedWarnings.updated(key, count + 1) + case _ => + // conditional warnings that are not enabled are not fatal + val d = dia match + case w: Warning if ctx.settings.XfatalWarnings.value => w.toError + case _ => dia + if !isHidden(d) then // avoid isHidden test for summarized warnings so that message is not forced + withMode(Mode.Printing)(doReport(d)) + d match { + case _: Warning => _warningCount += 1 + case e: Error => + errors = e :: errors + _errorCount += 1 + if ctx.typerState.isGlobalCommittable then + ctx.base.errorsToBeReported = true + case _: Info => // nothing to do here + // match error if d is something else + } + end issueUnconfigured + def issueIfNotSuppressed(dia: Diagnostic)(using Context): Unit = def go() = import Action._ - - val toReport = dia match - case w: Warning => - def fatal(w: Warning) = if ctx.settings.XfatalWarnings.value && !w.isSummarizedConditional then Some(w.toError) else Some(w) - if ctx.settings.silentWarnings.value then None - else WConf.parsed.action(dia) match - case Silent => None - case Info => Some(w.toInfo) - case Warning => fatal(w) - case Verbose => fatal(w).tap(_.foreach(_.setVerbose())) - case Error => Some(w.toError) - case _ => Some(dia) - - toReport foreach { - case cw: ConditionalWarning if cw.isSummarizedConditional => - val key = cw.enablingOption.name - unreportedWarnings = - unreportedWarnings.updated(key, unreportedWarnings.getOrElse(key, 0) + 1) - case d if !isHidden(d) => - withMode(Mode.Printing)(doReport(d)) - d match { - case _: Warning => _warningCount += 1 - case e: Error => - errors = e :: errors - _errorCount += 1 - if ctx.typerState.isGlobalCommittable then - ctx.base.errorsToBeReported = true - case _: Info => // nothing to do here - // match error if d is something else - } - case _ => // hidden - } - end go + dia match + case w: Warning => WConf.parsed.action(w) match + case Error => issueUnconfigured(w.toError) + case Warning => issueUnconfigured(w) + case Verbose => issueUnconfigured(w.setVerbose()) + case Info => issueUnconfigured(w.toInfo) + case Silent => + case _ => issueUnconfigured(dia) // `ctx.run` can be null in test, also in the repl when parsing the first line. The parser runs early, the Run is // only created in ReplDriver.compile when a line is submitted. This means that `@nowarn` doesnt work on parser diff --git a/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala b/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala index d3c334599666..db39ed6527d1 100644 --- a/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala @@ -17,7 +17,7 @@ import Diagnostic._ * - The reporter is not flushed and the message containers capture a * `Context` (about 4MB) */ -class StoreReporter(outer: Reporter = Reporter.NoReporter) extends Reporter { +class StoreReporter(outer: Reporter = Reporter.NoReporter, fromTyperState: Boolean = false) extends Reporter { protected var infos: mutable.ListBuffer[Diagnostic] = null @@ -40,4 +40,11 @@ class StoreReporter(outer: Reporter = Reporter.NoReporter) extends Reporter { override def pendingMessages(using Context): List[Diagnostic] = if (infos != null) infos.toList else Nil override def errorsReported: Boolean = hasErrors || (outer != null && outer.errorsReported) + + // If this is a TyperState buffering reporter then buffer the messages, + // so that then only when the messages are unbuffered (when the reporter if flushed) + // do they go through -Wconf, and possibly then buffered on the Run as a suspended message + override def report(dia: Diagnostic)(using Context): Unit = + if fromTyperState then issueUnconfigured(dia) + else super.report(dia) } diff --git a/compiler/src/dotty/tools/dotc/reporting/TestReporter.scala b/compiler/src/dotty/tools/dotc/reporting/TestReporter.scala index 8ad5b525de5c..a3d84e462bf0 100644 --- a/compiler/src/dotty/tools/dotc/reporting/TestReporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/TestReporter.scala @@ -6,7 +6,7 @@ import collection.mutable import Diagnostic._ /** A re-usable Reporter used in Contexts#test */ -class TestingReporter extends StoreReporter(null): +class TestingReporter extends StoreReporter(null, fromTyperState = false): infos = new mutable.ListBuffer[Diagnostic] override def hasUnreportedErrors: Boolean = infos.exists(_.isInstanceOf[Error]) def reset(): Unit = infos.clear() From 57a21adc2e9d45987e671a22f99cb87b788c0b1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Zyba=C5=82a?= Date: Mon, 8 Nov 2021 11:08:57 +0100 Subject: [PATCH 0821/1244] Add source position for errors from doc-root-content file --- .../tools/scaladoc/tasty/comments/Comments.scala | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala index 52093e42a6f0..e3df52b11d61 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala @@ -88,6 +88,11 @@ abstract class MarkupConversion[T](val repr: Repr)(using dctx: DocContext) { if repr == null then null.asInstanceOf[qctx.reflect.Symbol] else repr.sym private given qctx.type = qctx + lazy val srcPos = if owner == qctx.reflect.defn.RootClass then { + val sourceFile = dctx.args.rootDocPath.map(p => dotty.tools.dotc.util.SourceFile(dotty.tools.io.AbstractFile.getFile(p), scala.io.Codec.UTF8)) + sourceFile.fold(dotty.tools.dotc.util.NoSourcePosition)(sf => dotty.tools.dotc.util.SourcePosition(sf, dotty.tools.dotc.util.Spans.NoSpan)) + } else owner.pos.get.asInstanceOf[dotty.tools.dotc.util.SrcPos] + object SymOpsWithLinkCache extends SymOpsWithLinkCache export SymOpsWithLinkCache._ import SymOps._ @@ -96,8 +101,7 @@ abstract class MarkupConversion[T](val repr: Repr)(using dctx: DocContext) { if SchemeUri.matches(queryStr) then DocLink.ToURL(queryStr) else QueryParser(queryStr).tryReadQuery() match case Left(err) => - // TODO convert owner.pos to get to the comment, add stack trace - report.warning(s"Unable to parse query `$queryStr`: ${err.getMessage}") + report.warning(s"Unable to parse query `$queryStr`: ${err.getMessage}", srcPos) val msg = s"Unable to parse query: ${err.getMessage}" DocLink.UnresolvedDRI(queryStr, msg) case Right(query) => @@ -112,7 +116,8 @@ abstract class MarkupConversion[T](val repr: Repr)(using dctx: DocContext) { val msg = s"$txt: $queryStr" if (!summon[DocContext].args.noLinkWarnings) then - report.warning(msg, owner.pos.get.asInstanceOf[dotty.tools.dotc.util.SrcPos]) + + report.warning(msg, srcPos) DocLink.UnresolvedDRI(queryStr, txt) From be318fb711ecae2beac4be15db0856e733d9b5ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Zyba=C5=82a?= Date: Mon, 8 Nov 2021 11:29:28 +0100 Subject: [PATCH 0822/1244] Fix double implicit modifier --- scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala index 6e80c164d1d9..e412475cbf2c 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala @@ -100,7 +100,7 @@ object SymOps: Flags.Case -> Modifier.Case, ).collect { case (flag, mod) if sym.flags.is(flag) => mod - } ++ Seq(Modifier.Implicit).filter(_ => sym.isImplicitClass) + } def isHiddenByVisibility(using dctx: DocContext): Boolean = import VisibilityScope._ From e9ae876e00ee235b178e7fc29ac0677bc43f32b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Zyba=C5=82a?= Date: Fri, 12 Nov 2021 11:20:23 +0100 Subject: [PATCH 0823/1244] Add test for implicit class --- scaladoc-testcases/src/tests/classModifiers.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scaladoc-testcases/src/tests/classModifiers.scala b/scaladoc-testcases/src/tests/classModifiers.scala index a189c0e0c53b..c129ef92de2c 100644 --- a/scaladoc-testcases/src/tests/classModifiers.scala +++ b/scaladoc-testcases/src/tests/classModifiers.scala @@ -11,3 +11,5 @@ sealed case class D(c: String) final case class E(c: String) open class F + +implicit class Foo(i: Int) From e433a9b2dc2b53691a2258ff3c86be3b6cd87e54 Mon Sep 17 00:00:00 2001 From: comcx Date: Sun, 14 Nov 2021 15:51:28 +0800 Subject: [PATCH 0824/1244] fix typo in doc --- compiler/src/dotty/tools/dotc/core/Names.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 97356c76dde8..f12aaecdd12d 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -245,7 +245,7 @@ object Names { myMangledString } - /** If this a qualified name, split it into underlyng, last part, and separator + /** If this a qualified name, split it into underlying, last part, and separator * Otherwise return an empty name, the name itself, and "") */ def split: (TermName, TermName, String) From 6f2b8da2be1542ce63ce3c1b07a66d9102063220 Mon Sep 17 00:00:00 2001 From: Arthur Sengileyev Date: Mon, 25 Oct 2021 14:20:57 +0300 Subject: [PATCH 0825/1244] Consider minTargetVersion as always supported --- compiler/src/dotty/tools/dotc/config/ScalaSettings.scala | 2 +- compiler/test/dotty/tools/dotc/CompilationTests.scala | 2 ++ tests/neg-custom-args/jdk-9-app.check | 6 ++++++ tests/neg-custom-args/jdk-9-app.scala | 5 +++++ tests/pos-custom-args/jdk-8-app.scala | 5 +++++ 5 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 tests/neg-custom-args/jdk-9-app.check create mode 100644 tests/neg-custom-args/jdk-9-app.scala create mode 100644 tests/pos-custom-args/jdk-8-app.scala diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index d66c5d7ab4c2..13adb0165c77 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -24,7 +24,7 @@ object ScalaSettings: val jdkVersion = JDK9Reflectors.runtimeVersionMajor(JDK9Reflectors.runtimeVersion()).intValue() val maxVersion = Math.min(jdkVersion, maxTargetVersion) (minTargetVersion to maxVersion).toList.map(_.toString) - else List() + else List(minTargetVersion).map(_.toString) def defaultClasspath: String = sys.env.getOrElse("CLASSPATH", ".") diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index 06526aa6a924..4a85d863ed9f 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -64,6 +64,7 @@ class CompilationTests { compileFile("tests/pos-custom-args/help.scala", defaultOptions.and("-help", "-V", "-W", "-X", "-Y")), compileFile("tests/pos-custom-args/i10383.scala", defaultOptions.and("-source", "future", "-deprecation", "-Xfatal-warnings")), compileFile("tests/pos-custom-args/i13044.scala", defaultOptions.and("-Xmax-inlines:33")), + compileFile("tests/pos-custom-args/jdk-8-app.scala", defaultOptions.and("-release:8")), ).checkCompile() } @@ -184,6 +185,7 @@ class CompilationTests { compileDir("tests/neg-custom-args/hidden-type-errors", defaultOptions.and("-explain")), compileFile("tests/neg-custom-args/i13026.scala", defaultOptions.and("-print-lines")), compileFile("tests/neg-custom-args/i13838.scala", defaultOptions.and("-Ximplicit-search-limit", "1000")), + compileFile("tests/neg-custom-args/jdk-9-app.scala", defaultOptions.and("-release:8")), ).checkExpectedErrors() } diff --git a/tests/neg-custom-args/jdk-9-app.check b/tests/neg-custom-args/jdk-9-app.check new file mode 100644 index 000000000000..e2b94e2cb115 --- /dev/null +++ b/tests/neg-custom-args/jdk-9-app.check @@ -0,0 +1,6 @@ +-- [E006] Not Found Error: tests/neg-custom-args/jdk-9-app.scala:4:10 -------------------------------------------------- +4 | println(ProcessHandle.current().pid()) // error: not found + | ^^^^^^^^^^^^^ + | Not found: ProcessHandle + +longer explanation available when compiling with `-explain` diff --git a/tests/neg-custom-args/jdk-9-app.scala b/tests/neg-custom-args/jdk-9-app.scala new file mode 100644 index 000000000000..3dfd55332492 --- /dev/null +++ b/tests/neg-custom-args/jdk-9-app.scala @@ -0,0 +1,5 @@ +import java.lang.ProcessHandle + +object Jdk9App extends App { + println(ProcessHandle.current().pid()) // error: not found +} diff --git a/tests/pos-custom-args/jdk-8-app.scala b/tests/pos-custom-args/jdk-8-app.scala new file mode 100644 index 000000000000..6a9d07155958 --- /dev/null +++ b/tests/pos-custom-args/jdk-8-app.scala @@ -0,0 +1,5 @@ +import java.time.LocalDate + +object Jdk8App extends App { + println(LocalDate.now()) +} From bf0ecd36be86c0ad31951f51147bac3c4e68023d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 5 Nov 2021 11:19:08 +0100 Subject: [PATCH 0826/1244] Try to instantiate type variables in tryInsertImplicitOnQualifier Fixes #13842 What happened in #13842 was that we were not hitting this case in `tryWiden`, which is a method in ApproximatingTypeMap that tries to dealias or widen before propagating a Range outwards: ```scala case info: SingletonType => // if H#x: y.type, then for any x in L..H, x.type =:= y.type, // hence we can replace with y.type under all variances reapply(info) ``` The actual info here was a TypeVar with a singleton type as lower bound. Instantiating the TypeVar produces a SingletonType and case applies. We cannot really instantiate TypeVars here since this is very low-level code. For instance we might be in a state where the instantiation is provisional and the TyperState is thrown away. But AsSeenFrom results are cached so we'd have the wrong type in the caches. What we do instead is add an additional case in `tryInsertImplicitOnQualifier` which is the last resort when an application fails. Here, if we can instantiate some type variables in the qualifier, we try again. --- .../dotty/tools/dotc/typer/Inferencing.scala | 16 +++++---- .../src/dotty/tools/dotc/typer/Typer.scala | 35 +++++++++++++------ .../test/dotc/pos-test-pickling.blacklist | 4 +++ tests/pos/i13842.scala | 14 ++++++++ 4 files changed, 53 insertions(+), 16 deletions(-) create mode 100644 tests/pos/i13842.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala index d0565857db91..c544a0423d51 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala @@ -96,8 +96,12 @@ object Inferencing { * their instantiation could uncover new type members. However that search is best * effort only. It might miss type variables that appear in structures involving * alias types and type projections. + * @param applied Test is done in a `tryInsertImplicitOnQualifier` application. + * In this case, we always try to instantiate TypeVars in type arguments. + * If `applied` is false, we only try that in arguments that may affect + * the result type. */ - def couldInstantiateTypeVar(tp: Type)(using Context): Boolean = tp.dealias match + def couldInstantiateTypeVar(tp: Type, applied: Boolean = false)(using Context): Boolean = tp.dealias match case tvar: TypeVar if !tvar.isInstantiated && ctx.typerState.constraint.contains(tvar) @@ -120,14 +124,14 @@ object Inferencing { case _ => Nil case _ => Nil case _ => Nil - couldInstantiateTypeVar(tycon) - || argsInResult.exists(couldInstantiateTypeVar) + couldInstantiateTypeVar(tycon, applied) + || (if applied then args else argsInResult).exists(couldInstantiateTypeVar(_, applied)) case RefinedType(parent, _, _) => - couldInstantiateTypeVar(parent) + couldInstantiateTypeVar(parent, applied) case tp: AndOrType => - couldInstantiateTypeVar(tp.tp1) || couldInstantiateTypeVar(tp.tp2) + couldInstantiateTypeVar(tp.tp1, applied) || couldInstantiateTypeVar(tp.tp2, applied) case AnnotatedType(tp, _) => - couldInstantiateTypeVar(tp) + couldInstantiateTypeVar(tp, applied) case _ => false diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 4c2533d6dbba..6177faf6b6b0 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -81,6 +81,12 @@ object Typer { */ private val InsertedApply = new Property.Key[Unit] + /** An attachment on a result of an implicit conversion or extension method + * that was added by tryInsertImplicitOnQualifier. Needed to prevent infinite + * expansions in error cases (e.g. in fuzzy/i9293.scala). + */ + private val InsertedImplicitOnQualifier = new Property.Key[Unit] + /** An attachment on a tree `t` occurring as part of a `t()` where * the `()` was dropped by the Typer. */ @@ -3141,21 +3147,30 @@ class Typer extends Namer } /** If this tree is a select node `qual.name` (possibly applied to type variables) - * that does not conform to `pt`, try to insert an implicit conversion `c` around - * `qual` so that `c(qual).name` conforms to `pt`. + * that does not conform to `pt`, try two mitigations: + * 1. Instantiate any TypeVars in the widened type of `tree` with their lower bounds. + * 2. Try to insert an implicit conversion `c` around `qual` so that + * `c(qual).name` conforms to `pt`. */ def tryInsertImplicitOnQualifier(tree: Tree, pt: Type, locked: TypeVars)(using Context): Option[Tree] = trace(i"try insert impl on qualifier $tree $pt") { tree match case tree @ Select(qual, name) if name != nme.CONSTRUCTOR => - val selProto = SelectionProto(name, pt, NoViewsAllowed, privateOK = false) - if selProto.isMatchedBy(qual.tpe) then None + if couldInstantiateTypeVar(qual.tpe.widen, applied = true) + then + Some(adapt(tree, pt, locked)) else - tryEither { - val tree1 = tryExtensionOrConversion(tree, pt, pt, qual, locked, NoViewsAllowed, inSelect = false) - if tree1.isEmpty then None - else Some(adapt(tree1, pt, locked)) - } { (_, _) => None - } + val selProto = SelectionProto(name, pt, NoViewsAllowed, privateOK = false) + if selProto.isMatchedBy(qual.tpe) || tree.hasAttachment(InsertedImplicitOnQualifier) then + None + else + tryEither { + val tree1 = tryExtensionOrConversion(tree, pt, pt, qual, locked, NoViewsAllowed, inSelect = false) + if tree1.isEmpty then None + else + tree1.putAttachment(InsertedImplicitOnQualifier, ()) + Some(adapt(tree1, pt, locked)) + } { (_, _) => None + } case TypeApply(fn, args) if args.forall(_.isInstanceOf[untpd.InferredTypeTree]) => tryInsertImplicitOnQualifier(fn, pt, locked) case _ => None diff --git a/compiler/test/dotc/pos-test-pickling.blacklist b/compiler/test/dotc/pos-test-pickling.blacklist index 9c94e5968fce..42f2e417d759 100644 --- a/compiler/test/dotc/pos-test-pickling.blacklist +++ b/compiler/test/dotc/pos-test-pickling.blacklist @@ -68,6 +68,10 @@ i8182.scala # local lifted value in annotation argument has different position after pickling i2797a +# Late instantiation of type variable in tryInsertImplicitOnQualifier +# allows to simplify a type that was already computed +i13842.scala + # GADT cast applied to singleton type difference i4176-gadt.scala diff --git a/tests/pos/i13842.scala b/tests/pos/i13842.scala new file mode 100644 index 000000000000..7d29633619ec --- /dev/null +++ b/tests/pos/i13842.scala @@ -0,0 +1,14 @@ +class Parent { class E } + +object ChildA extends Parent + +object ChildB extends Parent + +class Printer[C <: Parent](val child: C): + def print22(e: child.E): String = "" + +def test = + Printer(ChildA).print22(new ChildA.E) // does not work + + //Printer[ChildA.type](ChildA).print22(new ChildA.E) // works + //val p = Printer(ChildA); p.print22(new ChildA.E) // works From bc6a743f9f47fb70b134a5352e266faeb86b6b0e Mon Sep 17 00:00:00 2001 From: Natsu Kagami Date: Wed, 13 Oct 2021 04:29:35 -0400 Subject: [PATCH 0827/1244] Fix for the secondary constructor parameters bug - Insert the parameters of the secondary constructor into the `Objekt` of `thisV`, so that they can be looked up when it is referenced. - Add tests --- .../tools/dotc/transform/init/Semantic.scala | 23 ++++++++++++++++--- tests/init/pos/second-ctor-fields.scala | 17 ++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 tests/init/pos/second-ctor-fields.scala diff --git a/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala b/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala index 4c88fd80bc3a..88794c609805 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala @@ -652,6 +652,15 @@ object Semantic { } def callConstructor(ctor: Symbol, args: List[ArgInfo], source: Tree): Contextual[Result] = log("call " + ctor.show + ", args = " + args, printer, (_: Result).show) { + // init "fake" param fields for the secondary constructor + def addParamsAsFields(env: Env, ref: Ref, ctorDef: DefDef) = { + val paramSyms = ctorDef.termParamss.flatten.map(_.symbol) + paramSyms.map { acc => + val value = env.lookup(acc) + ref.updateField(acc, value) + printer.println(acc.show + " initialized with " + value) + } + } value match { case Hot | Cold | _: RefSet | _: Fun => report.error("unexpected constructor call, meth = " + ctor + ", value = " + value, source) @@ -668,6 +677,7 @@ object Semantic { val tpl = cls.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template] init(tpl, ref, cls) else + addParamsAsFields(env, ref, ddef) val initCall = ddef.rhs match case Block(call :: _, _) => call case call => call @@ -682,12 +692,13 @@ object Semantic { given Trace = trace1 val cls = ctor.owner.enclosingClass.asClass val ddef = ctor.defTree.asInstanceOf[DefDef] - given Env= Env(ddef, args.map(_.value).widenArgs) + given Env = Env(ddef, args.map(_.value).widenArgs) if ctor.isPrimaryConstructor then val tpl = cls.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template] val res = withTrace(trace.add(cls.defTree)) { eval(tpl, ref, cls, cacheResult = true) } Result(ref, res.errors) else + addParamsAsFields(env, ref, ddef) eval(ddef.rhs, ref, cls, cacheResult = true) else if ref.canIgnoreMethodCall(ctor) then Result(Hot, Nil) @@ -752,19 +763,25 @@ object Semantic { Result(value2, errors) } } + end extension + extension (ref: Ref) def accessLocal(tmref: TermRef, klass: ClassSymbol, source: Tree): Contextual[Result] = val sym = tmref.symbol def default() = Result(Hot, Nil) if sym.is(Flags.Param) && sym.owner.isConstructor then + // if we can get the field from the Ref (which can only possibly be + // a secondary constructor parameter), then use it. + if (ref.objekt.hasField(sym)) + Result(ref.objekt.field(sym), Errors.empty) // instances of local classes inside secondary constructors cannot // reach here, as those values are abstracted by Cold instead of Warm. // This enables us to simplify the domain without sacrificing // expressiveness nor soundess, as local classes inside secondary // constructors are uncommon. - if sym.isContainedIn(klass) then + else if sym.isContainedIn(klass) then Result(env.lookup(sym), Nil) else // We don't know much about secondary constructor parameters in outer scope. @@ -777,7 +794,7 @@ object Semantic { case vdef: ValDef => // resolve this for local variable val enclosingClass = sym.owner.enclosingClass.asClass - val thisValue2 = resolveThis(enclosingClass, value, klass, source) + val thisValue2 = resolveThis(enclosingClass, ref, klass, source) thisValue2 match { case Hot => Result(Hot, Errors.empty) diff --git a/tests/init/pos/second-ctor-fields.scala b/tests/init/pos/second-ctor-fields.scala new file mode 100644 index 000000000000..70e7b46791b6 --- /dev/null +++ b/tests/init/pos/second-ctor-fields.scala @@ -0,0 +1,17 @@ + +class A(b: B) { + def this(b: B, m: Int) = { + this(b) + def foo = m // resolved to parameter `m` + class C { foo } // resolved to parameter `m`, as hidden field of `A` + new C + } +} + +class D(b: B) extends A(b, 10) { + val n = 10 +} + +class B { + val a = new D(this) +} From cd4db255ff27db8f2e75fc22b2773ad5fc364e53 Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Mon, 15 Nov 2021 09:57:02 +0100 Subject: [PATCH 0828/1244] move implementation of ordinal in enums to posttyper also add a check that ordinal is not implemented by the user, or mixed in by a trait - this is necessary as scala.deriving.Mirror.Sum delegates to ordinal method on an enum. Note that before this commit, as enum cases would previously declare ordinal methods at desugaring (without an override flag), refchecks would issue an override-without-override-modifier error anyway. Co-authored-by: Jamie Thompson Co-authored-by: Martin Odersky --- .../src/dotty/tools/dotc/ast/DesugarEnums.scala | 11 +++-------- .../src/dotty/tools/dotc/core/Definitions.scala | 1 + .../tools/dotc/transform/SyntheticMembers.scala | 14 +++++++++++++- .../src/dotty/tools/dotc/typer/Checking.scala | 13 +++++++++++++ tests/neg/enumsLabel-singleimpl.scala | 8 ++++---- tests/pos/i13554.scala | 6 ++++++ tests/pos/i13554a.scala | 15 +++++++++++++++ 7 files changed, 55 insertions(+), 13 deletions(-) create mode 100644 tests/pos/i13554.scala create mode 100644 tests/pos/i13554a.scala diff --git a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala index d47fd93abaf4..009aba09f2f6 100644 --- a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala +++ b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala @@ -179,13 +179,12 @@ object DesugarEnums { * } */ private def enumValueCreator(using Context) = { - val fieldMethods = if isJavaEnum then Nil else ordinalMeth(Ident(nme.ordinalDollar_)) :: Nil val creator = New(Template( constr = emptyConstructor, parents = enumClassRef :: scalaRuntimeDot(tpnme.EnumValue) :: Nil, derived = Nil, self = EmptyValDef, - body = fieldMethods + body = Nil ).withAttachment(ExtendsSingletonMirror, ())) DefDef(nme.DOLLAR_NEW, List(List(param(nme.ordinalDollar_, defn.IntType), param(nme.nameDollar, defn.StringType))), @@ -270,8 +269,6 @@ object DesugarEnums { def param(name: TermName, typ: Type)(using Context): ValDef = param(name, TypeTree(typ)) def param(name: TermName, tpt: Tree)(using Context): ValDef = ValDef(name, tpt, EmptyTree).withFlags(Param) - private def isJavaEnum(using Context): Boolean = enumClass.derivesFrom(defn.JavaEnumClass) - def ordinalMeth(body: Tree)(using Context): DefDef = DefDef(nme.ordinal, Nil, TypeTree(defn.IntType), body).withAddedFlags(Synthetic) @@ -290,10 +287,8 @@ object DesugarEnums { expandSimpleEnumCase(name, mods, definesLookups, span) else { val (tag, scaffolding) = nextOrdinal(name, CaseKind.Object, definesLookups) - val impl1 = cpy.Template(impl)( - parents = impl.parents :+ scalaRuntimeDot(tpnme.EnumValue), - body = if isJavaEnum then Nil else ordinalMethLit(tag) :: Nil - ).withAttachment(ExtendsSingletonMirror, ()) + val impl1 = cpy.Template(impl)(parents = impl.parents :+ scalaRuntimeDot(tpnme.EnumValue), body = Nil) + .withAttachment(ExtendsSingletonMirror, ()) val vdef = ValDef(name, TypeTree(), New(impl1)).withMods(mods.withAddedFlags(EnumValue, span)) flatTree(vdef :: scaffolding).withSpan(span) } diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 16ce0e381c75..d6c713039190 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -733,6 +733,7 @@ class Definitions { @tu lazy val NoneModule: Symbol = requiredModule("scala.None") @tu lazy val EnumClass: ClassSymbol = requiredClass("scala.reflect.Enum") + @tu lazy val Enum_ordinal: Symbol = EnumClass.requiredMethod(nme.ordinal) @tu lazy val EnumValueSerializationProxyClass: ClassSymbol = requiredClass("scala.runtime.EnumValueSerializationProxy") @tu lazy val EnumValueSerializationProxyConstructor: TermSymbol = diff --git a/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala b/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala index ac8d96afb604..3a94a78b3d8e 100644 --- a/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala +++ b/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala @@ -66,7 +66,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) { myCaseSymbols = defn.caseClassSynthesized myCaseModuleSymbols = myCaseSymbols.filter(_ ne defn.Any_equals) myEnumValueSymbols = List(defn.Product_productPrefix) - myNonJavaEnumValueSymbols = myEnumValueSymbols :+ defn.Any_toString + myNonJavaEnumValueSymbols = myEnumValueSymbols :+ defn.Any_toString :+ defn.Enum_ordinal } def valueSymbols(using Context): List[Symbol] = { initSymbols; myValueSymbols } @@ -132,6 +132,17 @@ class SyntheticMembers(thisPhase: DenotTransformer) { else // assume owner is `val Foo = new MyEnum { def ordinal = 0 }` Literal(Constant(clazz.owner.name.toString)) + def ordinalRef: Tree = + if isSimpleEnumValue then // owner is `def $new(_$ordinal: Int, $name: String) = new MyEnum { ... }` + ref(clazz.owner.paramSymss.head.find(_.name == nme.ordinalDollar_).get) + else // val CaseN = new MyEnum { ... def ordinal: Int = n } + val vdef = clazz.owner + val parentEnum = vdef.owner.companionClass + val children = parentEnum.children.zipWithIndex + val candidate: Option[Int] = children.collectFirst { case (child, idx) if child == vdef => idx } + assert(candidate.isDefined, i"could not find child for $vdef") + Literal(Constant(candidate.get)) + def toStringBody(vrefss: List[List[Tree]]): Tree = if (clazz.is(ModuleClass)) ownName else if (isNonJavaEnumValue) identifierRef @@ -143,6 +154,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) { case nme.toString_ => toStringBody(vrefss) case nme.equals_ => equalsBody(vrefss.head.head) case nme.canEqual_ => canEqualBody(vrefss.head.head) + case nme.ordinal => ordinalRef case nme.productArity => Literal(Constant(accessors.length)) case nme.productPrefix if isEnumValue => nameRef case nme.productPrefix => ownName diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 185b0584a5a2..6343f0bc4716 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -1217,8 +1217,19 @@ trait Checking { /** 1. Check that all case classes that extend `scala.reflect.Enum` are `enum` cases * 2. Check that parameterised `enum` cases do not extend java.lang.Enum. * 3. Check that only a static `enum` base class can extend java.lang.Enum. + * 4. Check that user does not implement an `ordinal` method in the body of an enum class. */ def checkEnum(cdef: untpd.TypeDef, cls: Symbol, firstParent: Symbol)(using Context): Unit = { + def existingDef(sym: Symbol, clazz: ClassSymbol)(using Context): Symbol = // adapted from SyntheticMembers + val existing = sym.matchingMember(clazz.thisType) + if existing != sym && !existing.is(Deferred) then existing else NoSymbol + def checkExistingOrdinal(using Context) = + val decl = existingDef(defn.Enum_ordinal, cls.asClass) + if decl.exists then + if decl.owner == cls then + report.error(em"the ordinal method of enum $cls can not be defined by the user", decl.srcPos) + else + report.error(em"enum $cls can not inherit the concrete ordinal method of ${decl.owner}", cdef.srcPos) def isEnumAnonCls = cls.isAnonymousClass && cls.owner.isTerm @@ -1238,6 +1249,8 @@ trait Checking { // this test allows inheriting from `Enum` by hand; // see enum-List-control.scala. report.error(ClassCannotExtendEnum(cls, firstParent), cdef.srcPos) + if cls.isEnumClass && !isJavaEnum then + checkExistingOrdinal } /** Check that the firstParent for an enum case derives from the declaring enum class, if not, adds it as a parent diff --git a/tests/neg/enumsLabel-singleimpl.scala b/tests/neg/enumsLabel-singleimpl.scala index 8f72a6cc71f2..a246ac9e5461 100644 --- a/tests/neg/enumsLabel-singleimpl.scala +++ b/tests/neg/enumsLabel-singleimpl.scala @@ -1,13 +1,13 @@ enum Ordinalled { - case A // error: method ordinal of type => Int needs `override` modifier + case A - def ordinal: Int = -1 + def ordinal: Int = -1 // error: the ordinal method of enum class Ordinalled can not be defined by the user } trait HasOrdinal { def ordinal: Int = 23 } -enum MyEnum extends HasOrdinal { - case Foo // error: method ordinal of type => Int needs `override` modifier +enum MyEnum extends HasOrdinal { // error: enum class MyEnum can not inherit the concrete ordinal method of trait HasOrdinal + case Foo } diff --git a/tests/pos/i13554.scala b/tests/pos/i13554.scala new file mode 100644 index 000000000000..e30d3eb9bd9f --- /dev/null +++ b/tests/pos/i13554.scala @@ -0,0 +1,6 @@ +object StatusCode: + class Matcher + +enum StatusCode(m: StatusCode.Matcher): + case InternalServerError extends StatusCode(???) + diff --git a/tests/pos/i13554a.scala b/tests/pos/i13554a.scala new file mode 100644 index 000000000000..0c6f0c6c972f --- /dev/null +++ b/tests/pos/i13554a.scala @@ -0,0 +1,15 @@ +object StatusCode: + enum Matcher: + case ServerError extends Matcher + end Matcher +end StatusCode + +enum StatusCode(code: Int, m: StatusCode.Matcher): + case InternalServerError extends StatusCode(500, StatusCode.Matcher.ServerError) +end StatusCode + +object Main { + def main(args: Array[String]): Unit = { + println(StatusCode.InternalServerError) + } +} From aec179f12d405307034b7a3771b3e6374c127117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Zyba=C5=82a?= Date: Fri, 12 Nov 2021 14:23:47 +0100 Subject: [PATCH 0829/1244] Add support for tables in wiki syntax --- .../src/example/level2/Documentation.scala | 13 + .../scaladoc/renderers/DocRenderer.scala | 19 + .../scaladoc/tasty/comments/Comments.scala | 1 + .../tasty/comments/wiki/Entities.scala | 9 + .../scaladoc/tasty/comments/wiki/Parser.scala | 396 +++++++++++++++--- .../src/dotty/tools/scaladoc/util/html.scala | 6 + 6 files changed, 392 insertions(+), 52 deletions(-) diff --git a/scaladoc-testcases/src/example/level2/Documentation.scala b/scaladoc-testcases/src/example/level2/Documentation.scala index cd8e13451df8..bbfd31669f3c 100644 --- a/scaladoc-testcases/src/example/level2/Documentation.scala +++ b/scaladoc-testcases/src/example/level2/Documentation.scala @@ -149,6 +149,19 @@ abstract class Documentation[T, A <: Int, B >: String, -X, +Y](c1: String, val c */ def loremIpsum[T](a: T): Map[T, T] = ??? + /** + *   + * | How to convert ... | to a [[PartialFunction]] | to an optional [[Function]] | to an extractor | + * | :---: | --- | --- | --- | + * | from a [[PartialFunction]] | [[Predef.identity]] | [[lift]] | [[Predef.identity]] | + * | from optional [[Function]] | [[Function1.UnliftOps#unlift]] or [[Function.unlift]] | [[Predef.identity]] | [[Function1.UnliftOps#unlift]] | + * | from an extractor | `{ case extractor(x) => x }` | `extractor.unapply _` | [[Predef.identity]] | + *   + * + * @syntax wiki + */ + def table(foo: String) = ??? + protected[example] val valWithScopeModifier = ??? protected[this] val valWithScopeModifierThis = ??? diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/DocRenderer.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/DocRenderer.scala index 03daa7acfe62..19e7e8a86995 100644 --- a/scaladoc/src/dotty/tools/scaladoc/renderers/DocRenderer.scala +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/DocRenderer.scala @@ -42,6 +42,16 @@ class DocRender(signatureRenderer: SignatureRenderer)(using DocContext): val tooltip = s"Problem linking $query: $msg" signatureRenderer.unresolvedLink(linkBody(query), titleAttr := tooltip) + private def renderHeader(header: Row): AppliedTag = + tr( + header.cells.map(c => th(c.blocks.map(renderElement))) + ) + + private def renderRow(row: Row): AppliedTag = + tr( + row.cells.map(c => td(c.blocks.map(renderElement))) + ) + private def renderElement(e: WikiDocElement): AppliedTag = e match case Title(text, level) => val content = renderElement(text) @@ -55,6 +65,15 @@ class DocRender(signatureRenderer: SignatureRenderer)(using DocContext): case Paragraph(text) => p(renderElement(text)) case Code(data: String) => pre(code(raw(data.escapeReservedTokens))) // TODO add classes case HorizontalRule => hr + case Table(header, columns, rows) => + table( + thead( + renderHeader(header) + ), + tbody( + rows.map(renderRow) + ) + ) case UnorderedList(items) => ul(listItems(items)) case OrderedList(items, style) => ol(listItems(items)) // TODO use style diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala index e3df52b11d61..261de910d4f6 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala @@ -235,6 +235,7 @@ class WikiCommentParser(repr: Repr)(using DocContext) case wiki.OrderedList(elems, _) => elems.headOption.fold("")(flatten) case wiki.DefinitionList(items) => items.headOption.fold("")(e => flatten(e._1)) case wiki.HorizontalRule => "" + case wiki.Table(header, columns, rows) => (header +: rows).flatMap(_.cells).flatMap(_.blocks).map(flatten).mkString def markupToString(str: wiki.Body) = str.blocks.headOption.fold("")(flatten) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/wiki/Entities.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/wiki/Entities.scala index 5cec60977813..f11e8095afe7 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/wiki/Entities.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/wiki/Entities.scala @@ -50,6 +50,15 @@ final case class UnorderedList(items: Seq[Block]) extends Block final case class OrderedList(items: Seq[Block], style: String) extends Block final case class DefinitionList(items: SortedMap[Inline, Block]) extends Block object HorizontalRule extends Block +final case class Table(header: Row, columnOptions: Seq[ColumnOption], rows: Seq[Row]) extends Block +final case class ColumnOption(option: 'L' | 'C' | 'R') +object ColumnOption { + val ColumnOptionLeft = ColumnOption('L') + val ColumnOptionCenter = ColumnOption('C') + val ColumnOptionRight = ColumnOption('R') +} +final case class Row(cells: Seq[Cell]) +final case class Cell(blocks: Seq[Block]) /** An section of text inside a block, possibly with formatting. */ sealed abstract class Inline extends WikiDocElement: diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/wiki/Parser.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/wiki/Parser.scala index 2436ca4e5239..a844f3384793 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/wiki/Parser.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/wiki/Parser.scala @@ -2,6 +2,7 @@ package dotty.tools.scaladoc package tasty.comments.wiki import scala.collection.mutable +import scala.annotation.tailrec import dotty.tools.scaladoc.tasty.comments.Regexes._ @@ -35,6 +36,8 @@ final class Parser( hrule() else if (checkList) listBlock() + else if (checkTableRow) + table() else { para() } @@ -127,6 +130,282 @@ final class Parser( HorizontalRule } + + /** Starts and end with a cell separator matching the minimal row || and all other possible rows */ + private val TableRow = """^\|.*\|$""".r + private val TableCellStart = "|" + + /* Checks for a well-formed table row */ + private def checkTableRow = { + check(TableCellStart) && { + val newlineIdx = buffer.indexOf('\n', offset) + newlineIdx != -1 && + TableRow.findFirstIn(buffer.substring(offset, newlineIdx)).isDefined + } + } + + /** {{{ + * table ::= headerRow '\n' delimiterRow '\n' dataRows '\n' + * content ::= inline-content + * row ::= '|' { content '|' }+ + * headerRow ::= row + * dataRows ::= row* + * align ::= ':' '-'+ | '-'+ | '-'+ ':' | ':' '-'+ ':' + * delimiterRow :: = '|' { align '|' }+ + * }}} + */ + def table(): Block = { + /* Helpers */ + + def peek(tag: String): Unit = { + val peek: String = buffer.substring(offset) + val limit = 60 + val limitedPeek = peek.substring(0, limit min peek.length) + println(s"peek: $tag: '$limitedPeek'") + } + + /* Accumulated state */ + + var header: Option[Row] = None + + val rows = mutable.ListBuffer.empty[Row] + + val cells = mutable.ListBuffer.empty[Cell] + + def finalizeCells(): Unit = { + if (cells.nonEmpty) { + rows += Row(cells.toList) + } + cells.clear() + } + + def finalizeHeaderCells(): Unit = { + if (cells.nonEmpty) { + if (header.isDefined) { + reportError("more than one table header") + } else { + header = Some(Row(cells.toList)) + } + } + cells.clear() + } + + val escapeChar = "\\" + + /* Poor man's negative lookbehind */ + def checkInlineEnd = + (check(TableCellStart) && !check(escapeChar, -1)) || check("\n") + + def decodeEscapedCellMark(text: String) = text.replace(escapeChar + TableCellStart, TableCellStart) + + def isEndOfText = char == endOfText + + //def isNewline = char == endOfLine + + //def skipNewline() = jump(endOfLine) + + def isStartMarkNewline = check(TableCellStart + endOfLine) + + def skipStartMarkNewline() = jump(TableCellStart + endOfLine) + + def isStartMark = check(TableCellStart) + + def skipStartMark() = jump(TableCellStart) + + def contentNonEmpty(content: Inline) = content != Text("") + + /* Parse cells of a table. + * @param cellStartMark The char indicating the start or end of a cell + * @param finalizeRow Function to invoke when the row has been fully parsed + */ + def parseCells(cellStartMark: String, finalizeRow: () => Unit): Unit = { + def jumpCellStartMark() = { + if (!jump(cellStartMark)) { + peek(s"Expected $cellStartMark") + sys.error(s"Precondition violated: Expected $cellStartMark.") + } + } + + val startPos = offset + + jumpCellStartMark() + + val content = Paragraph(getInline(isInlineEnd = checkInlineEnd, textTransform = decodeEscapedCellMark)) + + parseCells0(content :: Nil, finalizeRow, startPos, offset) + } + + // Continue parsing a table row. + // + // After reading inline content the following conditions will be encountered, + // + // Case : Next Chars + // .................. + // 1 : end-of-text + // 2 : '|' '\n' + // 3 : '|' + // 4 : '\n' + // + // Case 1. + // State : End of text + // Action: Store the current contents, close the row, report warning, stop parsing. + // + // Case 2. + // State : The cell separator followed by a newline + // Action: Store the current contents, skip the cell separator and newline, close the row, stop parsing. + // + // Case 3. + // State : The cell separator not followed by a newline + // Action: Store the current contents, skip the cell separator, continue parsing the row. + // + @tailrec def parseCells0( + contents: List[Block], + finalizeRow: () => Unit, + progressPreParse: Int, + progressPostParse: Int + ): Unit = { + + def storeContents() = cells += Cell(contents.reverse) + + val startPos = offset + + // The ordering of the checks ensures the state checks are correct. + if (progressPreParse == progressPostParse) { + peek("no-progress-table-row-parsing") + sys.error("No progress while parsing table row") + } else if (isEndOfText) { + // peek("1: end-of-text") + // Case 1 + storeContents() + finalizeRow() + reportError("unclosed table row") + } else if (isStartMarkNewline) { + // peek("2: start-mark-new-line/before") + // Case 2 + storeContents() + finalizeRow() + skipStartMarkNewline() + // peek("2: start-mark-new-line/after") + } else if (isStartMark) { + // peek("3: start-mark") + // Case 3 + storeContents() + skipStartMark() + val content = getInline(isInlineEnd = checkInlineEnd, textTransform = decodeEscapedCellMark) + // TrailingCellsEmpty produces empty content + val accContents = if (contentNonEmpty(content)) Paragraph(content) :: Nil else Nil + parseCells0(accContents, finalizeRow, startPos, offset) + } else { + // Case π√ⅈ + // When the impossible happens leave some clues. + reportError("unexpected table row markdown") + peek("parseCell0") + storeContents() + finalizeRow() + } + } + + /* Parsing */ + + jumpWhitespace() + + parseCells(TableCellStart, () => finalizeHeaderCells()) + + while (checkTableRow) { + val initialOffset = offset + + parseCells(TableCellStart, () => finalizeCells()) + + /* Progress should always be made */ + if (offset == initialOffset) { + peek("no-progress-table-parsing") + sys.error("No progress while parsing table") + } + } + + /* Finalize */ + + /* Structural consistency checks and coercion */ + + // https://github.github.com/gfm/#tables-extension- + // TODO: The header row must match the delimiter row in the number of cells. If not, a table will not be recognized: + // TODO: Break at following block level element: The table is broken at the first empty line, or beginning of another block-level structure: + // TODO: Do not return a table when: The header row must match the delimiter row in the number of cells. If not, a table will not be recognized + + if (cells.nonEmpty) { + reportError(s"Parsed and unused content: $cells") + } + assert(header.isDefined, "table header was not parsed") + val enforcedCellCount = header.get.cells.size + + def applyColumnCountConstraint(row: Row, defaultCell: Cell, rowType: String): Row = { + if (row.cells.size == enforcedCellCount) + row + else if (row.cells.size > enforcedCellCount) { + val excess = row.cells.size - enforcedCellCount + reportError(s"Dropping $excess excess table $rowType cells from row.") + Row(row.cells.take(enforcedCellCount)) + } else { + val missing = enforcedCellCount - row.cells.size + Row(row.cells ++ List.fill(missing)(defaultCell)) + } + } + + // TODO: Abandon table parsing when the delimiter is missing instead of fixing and continuing. + val delimiterRow :: dataRows = { + if (rows.nonEmpty) rows.toList + else { + reportError("Fixing missing delimiter row") + Row(Cell(Paragraph(Text("-")) :: Nil) :: Nil) :: Nil + } + } + + if (delimiterRow.cells.isEmpty) sys.error("TODO: Handle table with empty delimiter row") + + val constrainedDelimiterRow = applyColumnCountConstraint(delimiterRow, delimiterRow.cells(0), "delimiter") + + val constrainedDataRows = dataRows.map(applyColumnCountConstraint(_, Cell(Nil), "data")) + + /* Convert the row following the header row to column options */ + + val leftAlignmentPattern = "^:?-++$".r + val centerAlignmentPattern = "^:-++:$".r + val rightAlignmentPattern = "^-++:$".r + + import ColumnOption._ + /* Encourage user to fix by defaulting to least ignorable fix. */ + val defaultColumnOption = ColumnOptionRight + val columnOptions = constrainedDelimiterRow.cells.map { + alignmentSpecifier => + alignmentSpecifier.blocks match { + // TODO: Parse the second row without parsing inline markdown + // TODO: Save pos when delimiter row is parsed and use here in reported errors + case Paragraph(Text(as)) :: Nil => + as.trim match { + case leftAlignmentPattern(_*) => ColumnOptionLeft + case centerAlignmentPattern(_*) => ColumnOptionCenter + case rightAlignmentPattern(_*) => ColumnOptionRight + case x => + reportError(s"Fixing invalid column alignment: $x") + defaultColumnOption + } + case x => + reportError(s"Fixing invalid column alignment: $x") + defaultColumnOption + } + } + + if (check("\n", -1)) { + prevChar() + } else { + peek("expected-newline-missing") + sys.error("table parsing left buffer in unexpected state") + } + + blockEnded("table") + Table(header.get, columnOptions, constrainedDataRows) + } + /** {{{ para ::= inline '\n' }}} */ def para(): Block = { val p = @@ -185,67 +464,67 @@ final class Parser( list mkString } - def getInline(isInlineEnd: => Boolean): Inline = { + def getInline(isInlineEnd: => Boolean, textTransform: String => String = identity): Inline = { - def inline0(): Inline = { - if (char == safeTagMarker) { - val tag = htmlTag() - HtmlTag(tag.data + readHTMLFrom(tag)) - } - else if (check("'''")) bold() - else if (check("''")) italic() - else if (check("`")) monospace() - else if (check("__")) underline() - else if (check("^")) superscript() - else if (check(",,")) subscript() - else if (check("[[")) link() - else { - val str = readUntil { - char == safeTagMarker || - check("''") || - char == '`' || - check("__") || - char == '^' || - check(",,") || - check("[[") || - isInlineEnd || - checkParaEnded() || - char == endOfLine + def inline0(): Inline = { + if (char == safeTagMarker) { + val tag = htmlTag() + HtmlTag(tag.data + readHTMLFrom(tag)) + } + else if (check("'''")) bold() + else if (check("''")) italic() + else if (check("`")) monospace() + else if (check("__")) underline() + else if (check("^")) superscript() + else if (check(",,")) subscript() + else if (check("[[")) link() + else { + val str = readUntil { + char == safeTagMarker || + check("''") || + char == '`' || + check("__") || + char == '^' || + check(",,") || + check("[[") || + isInlineEnd || + checkParaEnded() || + char == endOfLine + } + Text(textTransform(str)) } - Text(str) } - } - val inlines: List[Inline] = { - val iss = mutable.ListBuffer.empty[Inline] - iss += inline0() - while (!isInlineEnd && !checkParaEnded()) { - val skipEndOfLine = if (char == endOfLine) { - nextChar() - true - } else { - false - } + val inlines: List[Inline] = { + val iss = mutable.ListBuffer.empty[Inline] + iss += inline0() + while (!isInlineEnd && !checkParaEnded()) { + val skipEndOfLine = if (char == endOfLine) { + nextChar() + true + } else { + false + } - val current = inline0() - (iss.last, current) match { - case (Text(t1), Text(t2)) if skipEndOfLine => - iss.update(iss.length - 1, Text(t1 + endOfLine + t2)) - case (i1, i2) if skipEndOfLine => - iss ++= List(Text(endOfLine.toString), i2) - case _ => iss += current + val current = inline0() + (iss.last, current) match { + case (Text(t1), Text(t2)) if skipEndOfLine => + iss.update(iss.length - 1, Text(t1 + endOfLine + t2)) + case (i1, i2) if skipEndOfLine => + iss ++= List(Text(endOfLine.toString), i2) + case _ => iss += current + } } + iss.toList } - iss.toList - } - inlines match { - case Nil => Text("") - case i :: Nil => i - case is => Chain(is) - } + inlines match { + case Nil => Text("") + case i :: Nil => i + case is => Chain(is) + } - } + } def htmlTag(): HtmlTag = { jump(safeTagMarker) @@ -371,6 +650,7 @@ final class Parser( checkSkipInitWhitespace('=') || checkSkipInitWhitespace("{{{") || checkList || + check(TableCellStart) || checkSkipInitWhitespace('\u003D') } offset = poff @@ -400,6 +680,10 @@ sealed class CharReader(buffer: String) { reader => final def nextChar() = offset += 1 + final def prevChar(): Unit = { + offset -= 1 + } + final def check(chars: String): Boolean = { val poff = offset val ok = jump(chars) @@ -407,6 +691,14 @@ sealed class CharReader(buffer: String) { reader => ok } + final def check(chars: String, checkOffset: Int): Boolean = { + val poff = offset + offset += checkOffset + val ok = jump(chars) + offset = poff + ok + } + def checkSkipInitWhitespace(c: Char): Boolean = { val poff = offset jumpWhitespace() diff --git a/scaladoc/src/dotty/tools/scaladoc/util/html.scala b/scaladoc/src/dotty/tools/scaladoc/util/html.scala index 63810af47fcd..790891b95d99 100644 --- a/scaladoc/src/dotty/tools/scaladoc/util/html.scala +++ b/scaladoc/src/dotty/tools/scaladoc/util/html.scala @@ -82,6 +82,12 @@ object HTML: val li = Tag("li") val code = Tag("code") val pre = Tag("pre") + val table = Tag("table") + val thead = Tag("thead") + val tbody = Tag("tbody") + val th = Tag("th") + val tr = Tag("tr") + val td = Tag("td") val cls = Attr("class") val href = Attr("href") From d3fe48e70b8db95fc05267bb9d95c8486e1920eb Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Wed, 1 Sep 2021 18:40:19 -0700 Subject: [PATCH 0830/1244] Avoid shadowing of name 'name' --- .../dotty/tools/dotc/parsing/Scanners.scala | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index 84a181769e3b..e36773d4f61d 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -242,24 +242,17 @@ object Scanners { /** A buffer for comments */ private val commentBuf = CharBuffer() - private def handleMigration(keyword: Token): Token = - if scala3keywords.contains(keyword) && migrateTo3 then treatAsIdent() - else keyword - - private def treatAsIdent(): Token = - val name0 = name // don't capture the `name` var in the message closure, it may be null later - report.errorOrMigrationWarning( - i"$name0 is now a keyword, write `$name0` instead of $name0 to keep it as an identifier", - sourcePos()) - patch(source, Span(offset), "`") - patch(source, Span(offset + name.length), "`") - IDENTIFIER - - def toToken(name: SimpleName): Token = { - val idx = name.start + def toToken(identifier: SimpleName): Token = + def handleMigration(keyword: Token): Token = + if scala3keywords.contains(keyword) && migrateTo3 then + report.errorOrMigrationWarning(i"$identifier is now a keyword, write `$identifier` instead of $identifier to keep it as an identifier", sourcePos()) + patch(source, Span(offset), "`") + patch(source, Span(offset + identifier.length), "`") + IDENTIFIER + else keyword + val idx = identifier.start if (idx >= 0 && idx <= lastKeywordStart) handleMigration(kwArray(idx)) else IDENTIFIER - } def newTokenData: TokenData = new TokenData {} From 21ffafecd92104dda4d19276f12fb2f35d38589f Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Wed, 1 Sep 2021 20:00:05 -0700 Subject: [PATCH 0831/1244] Use tokenString --- compiler/src/dotty/tools/dotc/parsing/Scanners.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index e36773d4f61d..7e9362af5493 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -245,7 +245,8 @@ object Scanners { def toToken(identifier: SimpleName): Token = def handleMigration(keyword: Token): Token = if scala3keywords.contains(keyword) && migrateTo3 then - report.errorOrMigrationWarning(i"$identifier is now a keyword, write `$identifier` instead of $identifier to keep it as an identifier", sourcePos()) + val what = tokenString(keyword) + report.errorOrMigrationWarning(i"$what is now a keyword, write `$what` instead of $what to keep it as an identifier", sourcePos()) patch(source, Span(offset), "`") patch(source, Span(offset + identifier.length), "`") IDENTIFIER From f6c9264986ba5ee5cd22861b74a0e3bed07a85b8 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Wed, 1 Sep 2021 20:13:35 -0700 Subject: [PATCH 0832/1244] Distinguish simple finishNamed from fiddly finishNamedToken --- .../src/dotty/tools/dotc/parsing/Scanners.scala | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index 7e9362af5493..0fa71dd02a8b 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -135,10 +135,13 @@ object Scanners { */ protected def putChar(c: Char): Unit = litBuf.append(c) - /** Clear buffer and set name and token - * If `target` is different from `this`, don't treat identifiers as end tokens + /** Finish an IDENTIFIER with `this.name`. */ + inline def finishNamed(): Unit = finishNamedToken(IDENTIFIER, this) + + /** Clear buffer and set name and token. + * If `target` is different from `this`, don't treat identifiers as end tokens. */ - def finishNamed(idtoken: Token = IDENTIFIER, target: TokenData = this): Unit = + def finishNamedToken(idtoken: Token, target: TokenData): Unit = target.name = termName(litBuf.chars, 0, litBuf.length) litBuf.clear() target.token = idtoken @@ -996,7 +999,7 @@ object Scanners { getLitChars('`') if (ch == '`') { nextChar() - finishNamed(BACKQUOTED_IDENT) + finishNamedToken(BACKQUOTED_IDENT, target = this) if (name.length == 0) error("empty quoted identifier") else if (name == nme.WILDCARD) @@ -1162,7 +1165,7 @@ object Scanners { nextRawChar() ch != SU && Character.isUnicodeIdentifierPart(ch) do () - finishNamed(target = next) + finishNamedToken(IDENTIFIER, target = next) } else error("invalid string interpolation: `$$`, `$\"`, `$`ident or `$`BlockExpr expected") From 18dee7b1f3c1cf06e946cfb99124c675ba4126f5 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Wed, 1 Sep 2021 21:53:31 -0700 Subject: [PATCH 0833/1244] Test interpolation of keyword --- tests/neg-custom-args/fatal-warnings/i13440.check | 12 ++++++++++-- tests/neg-custom-args/fatal-warnings/i13440.scala | 6 +++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/tests/neg-custom-args/fatal-warnings/i13440.check b/tests/neg-custom-args/fatal-warnings/i13440.check index 0e9dd7dd5e50..fde8133419b6 100644 --- a/tests/neg-custom-args/fatal-warnings/i13440.check +++ b/tests/neg-custom-args/fatal-warnings/i13440.check @@ -1,4 +1,12 @@ --- Error: tests/neg-custom-args/fatal-warnings/i13440.scala:3:13 ------------------------------------------------------- -3 |case class A(enum: List[Int] = Nil) // error +-- Error: tests/neg-custom-args/fatal-warnings/i13440.scala:3:4 -------------------------------------------------------- +3 |def given = 42 // error + | ^ + | given is now a keyword, write `given` instead of given to keep it as an identifier +-- Error: tests/neg-custom-args/fatal-warnings/i13440.scala:5:13 ------------------------------------------------------- +5 |case class C(enum: List[Int] = Nil) { // error | ^ | enum is now a keyword, write `enum` instead of enum to keep it as an identifier +-- Error: tests/neg-custom-args/fatal-warnings/i13440.scala:6:11 ------------------------------------------------------- +6 | val s = s"$enum" // error + | ^ + | enum is now a keyword, write `enum` instead of enum to keep it as an identifier diff --git a/tests/neg-custom-args/fatal-warnings/i13440.scala b/tests/neg-custom-args/fatal-warnings/i13440.scala index 8e3af76ad3fa..6cb4956e7434 100644 --- a/tests/neg-custom-args/fatal-warnings/i13440.scala +++ b/tests/neg-custom-args/fatal-warnings/i13440.scala @@ -1,3 +1,7 @@ import language.`3.0-migration` -case class A(enum: List[Int] = Nil) // error +def given = 42 // error + +case class C(enum: List[Int] = Nil) { // error + val s = s"$enum" // error +} From 71f282714f1775042cc571d33d75963fc321e8a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Zyba=C5=82a?= Date: Tue, 16 Nov 2021 11:02:23 +0100 Subject: [PATCH 0834/1244] Add missing styles to snippets that are not Scala --- scaladoc-js/src/code-snippets/CodeSnippets.scala | 2 +- .../tasty/comments/markdown/SnippetRenderer.scala | 2 +- .../comments/markdown/SnippetRenderingExtension.scala | 8 ++++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/scaladoc-js/src/code-snippets/CodeSnippets.scala b/scaladoc-js/src/code-snippets/CodeSnippets.scala index 92e82b40957f..3d4b4af2ab64 100644 --- a/scaladoc-js/src/code-snippets/CodeSnippets.scala +++ b/scaladoc-js/src/code-snippets/CodeSnippets.scala @@ -20,7 +20,7 @@ class CodeSnippets: case _ => None } - def enrichSnippets() = document.querySelectorAll("div.snippet").foreach { + def enrichSnippets() = document.querySelectorAll("div.snippet[scala-snippet]").foreach { case snippet: html.Element => snippet.addEventListener("click", (e: MouseEvent) => e.asInstanceOf[js.Dynamic].fromSnippet = true) snippetAnchor(snippet) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SnippetRenderer.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SnippetRenderer.scala index 55f3ac31a7bb..a989cfa124e3 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SnippetRenderer.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SnippetRenderer.scala @@ -137,7 +137,7 @@ object SnippetRenderer: def renderSnippetWithMessages(snippetName: Option[String], codeLines: Seq[String], messages: Seq[SnippetCompilerMessage], hasContext: Boolean): String = val transformedLines = wrapCodeLines.andThen(addCompileMessages(messages)).apply(codeLines).map(_.toHTML) val codeHTML = s"""${transformedLines.mkString("")}""" - s"""

""" + s"""
$codeHTML
${snippetName.fold("")(snippetLabel(_))}
""" def renderSnippetWithMessages(node: ExtendedFencedCodeBlock): String = renderSnippetWithMessages( diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SnippetRenderingExtension.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SnippetRenderingExtension.scala index 7a7edc0f5e86..74d4f461dc7b 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SnippetRenderingExtension.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/comments/markdown/SnippetRenderingExtension.scala @@ -12,6 +12,7 @@ import com.vladsch.flexmark.util.ast._ import com.vladsch.flexmark.util.options._ import com.vladsch.flexmark.util.sequence.BasedSequence import com.vladsch.flexmark._ +import com.vladsch.flexmark.ast.FencedCodeBlock /** * SnippetRenderingExtension is responsible for running an analysis for scala codeblocks in the static documentation/scaladoc comments. @@ -26,10 +27,17 @@ object SnippetRenderingExtension extends HtmlRenderer.HtmlRendererExtension: SnippetRenderer.renderSnippetWithMessages(node) ) + object FencedCodeBlockHandler extends CustomNodeRenderer[FencedCodeBlock]: + override def render(node: FencedCodeBlock, c: NodeRendererContext, html: HtmlWriter): Unit = + html.raw("""
""") + c.delegateRender() + html.raw("""
""") + object Render extends NodeRenderer: override def getNodeRenderingHandlers: JSet[NodeRenderingHandler[_]] = JSet( new NodeRenderingHandler(classOf[ExtendedFencedCodeBlock], ExtendedFencedCodeBlockHandler), + new NodeRenderingHandler(classOf[FencedCodeBlock], FencedCodeBlockHandler) ) object Factory extends NodeRendererFactory: From c3d8006f1f8d35eb4932b337a5d2d3329d285b63 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 17 Nov 2021 10:42:29 +0100 Subject: [PATCH 0835/1244] Improve issue templates --- .github/ISSUE_TEMPLATE/bug.md | 6 ++++++ .github/ISSUE_TEMPLATE/crash.md | 6 ++++++ .github/ISSUE_TEMPLATE/syntax-highlight.md | 7 +++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index d6a891e1c518..e7c8bcc40527 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -14,6 +14,12 @@ If you're not sure what version you're using, run `print scalaVersion` from sbt ## Minimized code + + ```Scala println("hello, world") ``` diff --git a/.github/ISSUE_TEMPLATE/crash.md b/.github/ISSUE_TEMPLATE/crash.md index dc935e310548..390a57273260 100644 --- a/.github/ISSUE_TEMPLATE/crash.md +++ b/.github/ISSUE_TEMPLATE/crash.md @@ -14,6 +14,12 @@ If you're not sure what version you're using, run `print scalaVersion` from sbt ## Minimized code + + ```Scala println("hello, world") ``` diff --git a/.github/ISSUE_TEMPLATE/syntax-highlight.md b/.github/ISSUE_TEMPLATE/syntax-highlight.md index 17b720d4d2aa..722c8ed5fa73 100644 --- a/.github/ISSUE_TEMPLATE/syntax-highlight.md +++ b/.github/ISSUE_TEMPLATE/syntax-highlight.md @@ -1,10 +1,13 @@ --- name: Syntax highlighting -about: Please create a syntax highlighting issue here https://github.com/scala/vscode-scala-syntax/issues +about: '' title: '' labels: '' assignees: '' --- -Please create a syntax highlighting issue here: [scala/vscode-scala-syntax](https://github.com/scala/vscode-scala-syntax/issues). +Please create a syntax highlighting issue here +* VS Code / GitHub: https://github.com/scala/vscode-scala-syntax/issues +* IntelliJ: https://youtrack.jetbrains.com/issues/SCL?q=tag:%20%7BScala%203%7D%20tag:%20%7BSyntax%20Highlighting%7D +* highlight.js: https://github.com/highlightjs/highlight.js/issues \ No newline at end of file From 3f88a7b397987fb382e6f7f3f4e5059273b69a92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Wed, 3 Nov 2021 13:59:59 +0100 Subject: [PATCH 0836/1244] Fix #13860: Ignore bridges when looking for a default getter's attached method. --- .../dotty/tools/backend/sjs/JSCodeGen.scala | 2 +- .../compiler/RegressionTestScala3.scala | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala index 53885ba523ec..e30ddd9a55da 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala @@ -4706,7 +4706,7 @@ object JSCodeGen { if (!overloads.isOverloaded) overloads.symbol else - overloads.suchThat(_.is(HasDefaultParams)).symbol + overloads.suchThat(_.is(HasDefaultParams, butNot = Bridge)).symbol } } diff --git a/tests/sjs-junit/test/org/scalajs/testsuite/compiler/RegressionTestScala3.scala b/tests/sjs-junit/test/org/scalajs/testsuite/compiler/RegressionTestScala3.scala index 90d7df3ab281..08aa26726dc7 100644 --- a/tests/sjs-junit/test/org/scalajs/testsuite/compiler/RegressionTestScala3.scala +++ b/tests/sjs-junit/test/org/scalajs/testsuite/compiler/RegressionTestScala3.scala @@ -52,6 +52,13 @@ class RegressionTestScala3 { def intPlusString(x: String): String = 5 + x assertEquals("5bc", intPlusString("bc")) } + + @Test def defaultParamsInModuleDefWithBridgesIssue13860(): Unit = { + import Issue13860._ + + assertEquals(0L, Foo.bar().x) + assertEquals(5L, Foo.bar(5L).x) + } } object RegressionTestScala3 { @@ -100,6 +107,18 @@ object RegressionTestScala3 { import I._ def blah = i } + + object Issue13860 { + class Foo(var x: Long) + + trait Companion[A] { + def bar(x: Long = 0): A + } + + object Foo extends Companion[Foo] { + def bar(x: Long = 0): Foo = new Foo(x) + } + } } // This class needs to be at the top-level, not in an object, to reproduce the issue From 4b9e969ed6ae915e294d7a9666e85405685ced24 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 17 Nov 2021 09:00:16 +0100 Subject: [PATCH 0837/1244] Add regression test ConstructExpr and DestructExpr are used to construct and destruct case classes into and from tuples containing the expressions of their elements. --- .../contruct-desturct/ConstructExpr.scala | 45 ++++++++++++++++++ .../contruct-desturct/DestructExpr.scala | 47 +++++++++++++++++++ tests/pos-macros/contruct-desturct/Test.scala | 7 +++ 3 files changed, 99 insertions(+) create mode 100644 tests/pos-macros/contruct-desturct/ConstructExpr.scala create mode 100644 tests/pos-macros/contruct-desturct/DestructExpr.scala create mode 100644 tests/pos-macros/contruct-desturct/Test.scala diff --git a/tests/pos-macros/contruct-desturct/ConstructExpr.scala b/tests/pos-macros/contruct-desturct/ConstructExpr.scala new file mode 100644 index 000000000000..6a2a6f40f0c5 --- /dev/null +++ b/tests/pos-macros/contruct-desturct/ConstructExpr.scala @@ -0,0 +1,45 @@ +package scala.quoted +package util + +trait ConstructExpr[T] { + + type Elems <: Tuple + + def from(x: Elems)(using Quotes): Expr[T] + // def from(x: Tuple.Map[Elems, Expr])(using Quotes): Expr[T] // alternative + +} + +object ConstructExpr { + + def apply[T](using ce: ConstructExpr[T]): ce.type = ce + + /** Default implementation of `ConstructExpr[Tuple1[T]]` */ + given EmptyTupleConstructExpr[T: Type]: ConstructExpr[EmptyTuple] with { + type Elems = EmptyTuple + def from(x: Elems)(using Quotes): Expr[EmptyTuple] = + '{ EmptyTuple } + } + + /** Default implementation of `ConstructExpr[Tuple1[T]]` */ + given Tuple1ConstructExpr[T: Type]: ConstructExpr[Tuple1[T]] with { + type Elems = Tuple1[Expr[T]] + def from(x: Elems)(using Quotes): Expr[Tuple1[T]] = + '{ Tuple1[T](${x._1}) } + } + + /** Default implementation of `ConstructExpr[Tuple2[T1, T2]]` */ + given Tuple2ConstructExpr[T1: Type, T2: Type]: ConstructExpr[Tuple2[T1, T2]] with { + type Elems = (Expr[T1], Expr[T2]) + def from(x: Elems)(using Quotes): Expr[Tuple2[T1, T2]] = + '{ Tuple2[T1, T2](${x._1}, ${x._2}) } + } + + /** Default implementation of `ConstructExpr[Tuple3[T1, T2, T3]]` */ + given Tuple3ConstructExpr[T1: Type, T2: Type, T3: Type]: ConstructExpr[Tuple3[T1, T2, T3]] with { + type Elems = (Expr[T1], Expr[T2], Expr[T3]) + def from(x: Elems)(using Quotes): Expr[Tuple3[T1, T2, T3]] = + '{ Tuple3[T1, T2, T3](${x._1}, ${x._2}, ${x._3}) } + } + +} diff --git a/tests/pos-macros/contruct-desturct/DestructExpr.scala b/tests/pos-macros/contruct-desturct/DestructExpr.scala new file mode 100644 index 000000000000..b54be5e1116a --- /dev/null +++ b/tests/pos-macros/contruct-desturct/DestructExpr.scala @@ -0,0 +1,47 @@ +package scala.quoted +package util + +trait DestructExpr[T] { + + type Elems <: Tuple + + def unapply(x: Expr[T])(using Quotes): Option[Elems] + // def unapply(x: Expr[T])(using Quotes): Option[Tuple.Map[Elems, Expr]] // alternative + +} + +/** Default given instances of `DestructExpr` */ +object DestructExpr { + + def unapply[T](x: Expr[T])(using de: DestructExpr[T])(using Quotes): Option[de.Elems] = + de.unapply(x) + + + /** Default implementation of `DestructExpr[Tuple1[...]]` + * - Transform `'{Tuple1(x1)}` into `Some(Tuple1('{x1}))` + * - Otherwise returns `None` + */ + given DestructTuple1[T1](using Type[T1]): DestructExpr[Tuple1[T1]] with { + type Elems = Tuple1[Expr[T1]] + def unapply(x: Expr[Tuple1[T1]])(using Quotes) = x match { + case '{ new Tuple1[T1]($y) } => Some(Tuple1(y)) + case '{ Tuple1[T1]($y) } => Some(Tuple1(y)) + case _ => None + } + } + + /** Default implementation of `DestructExpr[Tuple2[...]]` + * - Transform `'{Tuple2(x1, x2)}` into `Some(Tuple2('{x1}, '{x2}))` + * - Otherwise returns `None` + */ + given DestructTuple2[T1, T2](using Type[T1], Type[T2]): DestructExpr[Tuple2[T1, T2]] with { + type Elems = (Expr[T1], Expr[T2]) + def unapply(x: Expr[Tuple2[T1, T2]])(using Quotes) = x match { + case '{ new Tuple2[T1, T2]($y1, $y2) } => Some(Tuple2(y1, y2)) + case '{ Tuple2[T1, T2]($y1, $y2) } => Some(Tuple2(y1, y2)) + case '{ ($y1: T1) -> ($y2: T2) } => Some(Tuple2(y1, y2)) + case _ => None + } + } + +} diff --git a/tests/pos-macros/contruct-desturct/Test.scala b/tests/pos-macros/contruct-desturct/Test.scala new file mode 100644 index 000000000000..a4d159ed7d35 --- /dev/null +++ b/tests/pos-macros/contruct-desturct/Test.scala @@ -0,0 +1,7 @@ +import scala.quoted.* +import scala.quoted.util.* + +def test(using Quotes) = + '{ Tuple2(1, 2) } match + case DestructExpr((a, b)) => + ConstructExpr[(Int, Int)].from((a, b)) From aa726d6b439839f5340a8c7abd672678e1126160 Mon Sep 17 00:00:00 2001 From: Tom Grigg Date: Tue, 16 Nov 2021 21:05:10 -0800 Subject: [PATCH 0838/1244] Bump sbt-sonatype in hopes of fixing timeout issues publishing nightlies --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index 4e70c7f3122a..1716bb51b7f1 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -4,7 +4,7 @@ addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.7.1") -addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.6") +addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.9.10") addSbtPlugin("com.jsuereth" % "sbt-pgp" % "2.0.0") From 98198e946d26e8dc685f330d08ad61627a99b41c Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Wed, 17 Nov 2021 15:40:05 +0100 Subject: [PATCH 0839/1244] Complete when improting same symbol multiple times This is related to https://github.com/lampepfl/dotty/issues/13623 - since it seems that Predef might be imported more than once, but this doesn't yet solve the issue. --- .../dotty/tools/dotc/interactive/Completion.scala | 13 +++++++++++-- .../dotty/tools/languageserver/CompletionTest.scala | 13 +++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/interactive/Completion.scala b/compiler/src/dotty/tools/dotc/interactive/Completion.scala index 68cc0b37fd56..b57c300defae 100644 --- a/compiler/src/dotty/tools/dotc/interactive/Completion.scala +++ b/compiler/src/dotty/tools/dotc/interactive/Completion.scala @@ -201,13 +201,22 @@ object Completion { mappings.foreach { (name, denotss) => val first = denotss.head + + // import a.c + def isSingleImport = denotss.length < 2 + // import a.C + // locally { import b.C } + def isImportedInDifferentScope = first.ctx.scope ne denotss(1).ctx.scope + // import a.C + // import a.C + def isSameSymbolImportedDouble = denotss.forall(_.denots == first.denots) + denotss.find(!_.ctx.isImportContext) match { // most deeply nested member or local definition if not shadowed by an import case Some(local) if local.ctx.scope == first.ctx.scope => resultMappings += name -> local.denots - // most deeply nested import if not shadowed by another import - case None if denotss.length < 2 || (denotss(1).ctx.scope ne first.ctx.scope) => + case None if isSingleImport || isImportedInDifferentScope || isSameSymbolImportedDouble => resultMappings += name -> first.denots case _ => diff --git a/language-server/test/dotty/tools/languageserver/CompletionTest.scala b/language-server/test/dotty/tools/languageserver/CompletionTest.scala index 6ef219187475..bc870e329f4f 100644 --- a/language-server/test/dotty/tools/languageserver/CompletionTest.scala +++ b/language-server/test/dotty/tools/languageserver/CompletionTest.scala @@ -404,6 +404,19 @@ class CompletionTest { .completion(m1, Set()) } + @Test def completeFromSameImportsForEqualNestingLevels: Unit = { + code"""object Foo { + | def xxxx(i: Int): Int = i + |} + |object Test { + | import Foo.xxxx + | import Foo.xxxx + | import Foo.xxxx + | val x = xx$m1 + |}""".withSource + .completion(m1, Set(("xxxx", Method, "(i: Int): Int"))) + } + @Test def preferLocalDefinitionToImportForEqualNestingLevels: Unit = { code"""object Foo { | val xxxx = 1 From 573e4e75059b71941fa1c7497cde4127fc7f28e1 Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Thu, 21 Oct 2021 13:20:12 +0000 Subject: [PATCH 0840/1244] Add spire to community build --- .gitmodules | 6 ++++++ community-build/community-projects/spire | 1 + .../src/scala/dotty/communitybuild/projects.scala | 8 ++++++++ .../scala/dotty/communitybuild/CommunityBuildTest.scala | 1 + library/src/scala/runtime/LazyVals.scala | 2 -- 5 files changed, 16 insertions(+), 2 deletions(-) create mode 160000 community-build/community-projects/spire diff --git a/.gitmodules b/.gitmodules index d93aab9aa8fe..dff9d04cf40d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -213,6 +213,12 @@ [submodule "community-build/community-projects/scala-java8-compat"] path = community-build/community-projects/scala-java8-compat url = https://github.com/dotty-staging/scala-java8-compat.git +<<<<<<< HEAD [submodule "community-build/community-projects/specs2"] path = community-build/community-projects/specs2 url = https://github.com/dotty-staging/specs2.git +======= +[submodule "community-build/community-projects/spire"] + path = community-build/community-projects/spire + url = https://github.com/typelevel/spire.git +>>>>>>> Add spire to community build diff --git a/community-build/community-projects/spire b/community-build/community-projects/spire new file mode 160000 index 000000000000..c98b32c6844f --- /dev/null +++ b/community-build/community-projects/spire @@ -0,0 +1 @@ +Subproject commit c98b32c6844f501491ab3a22d6f5be50b9b80c8d diff --git a/community-build/src/scala/dotty/communitybuild/projects.scala b/community-build/src/scala/dotty/communitybuild/projects.scala index 61c72f8088f0..46f0f4dd4eba 100644 --- a/community-build/src/scala/dotty/communitybuild/projects.scala +++ b/community-build/src/scala/dotty/communitybuild/projects.scala @@ -731,11 +731,19 @@ object projects: dependencies = List(scalaJava8Compat, scalatest) ) +<<<<<<< HEAD lazy val specs2 = SbtCommunityProject( project = "specs2", sbtTestCommand = "core/testOnly -- exclude ci", sbtPublishCommand = "core/publishLocal", dependencies = List() +======= + lazy val spire = SbtCommunityProject( + project = "spire", + sbtTestCommand = "test", + sbtPublishCommand = "publishLocal", + dependencies = List(cats, algebra, disciplineMunit) +>>>>>>> Add spire to community build ) end projects diff --git a/community-build/test/scala/dotty/communitybuild/CommunityBuildTest.scala b/community-build/test/scala/dotty/communitybuild/CommunityBuildTest.scala index 9b5c17e85965..4aad0e26d265 100644 --- a/community-build/test/scala/dotty/communitybuild/CommunityBuildTest.scala +++ b/community-build/test/scala/dotty/communitybuild/CommunityBuildTest.scala @@ -90,6 +90,7 @@ class CommunityBuildTestC: @Test def scas = projects.scas.run() @Test def sconfig = projects.sconfig.run() @Test def shapeless = projects.shapeless.run() + @Test def spire = projects.spire.run() @Test def sourcecode = projects.sourcecode.run() @Test def specs2 = projects.specs2.run() @Test def stdLib213 = projects.stdLib213.run() diff --git a/library/src/scala/runtime/LazyVals.scala b/library/src/scala/runtime/LazyVals.scala index eeb955faecae..85ca4f5cb3a0 100644 --- a/library/src/scala/runtime/LazyVals.scala +++ b/library/src/scala/runtime/LazyVals.scala @@ -1,7 +1,5 @@ package scala.runtime -import scala.language.unsafeNulls - /** * Helper methods used in thread-safe lazy vals. */ From c695c84fa8581ccae00c9e491beb0215a0aaee2d Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Thu, 21 Oct 2021 13:24:50 -0700 Subject: [PATCH 0841/1244] Remove algebra from spire deps --- .gitmodules | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.gitmodules b/.gitmodules index dff9d04cf40d..44c9f7bc39e6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -213,12 +213,6 @@ [submodule "community-build/community-projects/scala-java8-compat"] path = community-build/community-projects/scala-java8-compat url = https://github.com/dotty-staging/scala-java8-compat.git -<<<<<<< HEAD -[submodule "community-build/community-projects/specs2"] - path = community-build/community-projects/specs2 - url = https://github.com/dotty-staging/specs2.git -======= [submodule "community-build/community-projects/spire"] path = community-build/community-projects/spire url = https://github.com/typelevel/spire.git ->>>>>>> Add spire to community build From a74d05b0b00f5a32f6f033ff00d243840bd48068 Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Wed, 17 Nov 2021 11:07:40 -0500 Subject: [PATCH 0842/1244] Use dotty-staging repo --- .gitmodules | 2 +- .../src/scala/dotty/communitybuild/projects.scala | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.gitmodules b/.gitmodules index 44c9f7bc39e6..848021e16a1b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -215,4 +215,4 @@ url = https://github.com/dotty-staging/scala-java8-compat.git [submodule "community-build/community-projects/spire"] path = community-build/community-projects/spire - url = https://github.com/typelevel/spire.git + url = https://github.com/dotty-staging/spire.git diff --git a/community-build/src/scala/dotty/communitybuild/projects.scala b/community-build/src/scala/dotty/communitybuild/projects.scala index 46f0f4dd4eba..3ce8b22dd455 100644 --- a/community-build/src/scala/dotty/communitybuild/projects.scala +++ b/community-build/src/scala/dotty/communitybuild/projects.scala @@ -731,21 +731,19 @@ object projects: dependencies = List(scalaJava8Compat, scalatest) ) -<<<<<<< HEAD lazy val specs2 = SbtCommunityProject( project = "specs2", sbtTestCommand = "core/testOnly -- exclude ci", sbtPublishCommand = "core/publishLocal", dependencies = List() -======= + ) + lazy val spire = SbtCommunityProject( project = "spire", sbtTestCommand = "test", sbtPublishCommand = "publishLocal", dependencies = List(cats, algebra, disciplineMunit) ->>>>>>> Add spire to community build ) - end projects def allProjects = List( From c12760b77b9c8ed678f153e1438a186db30ca53f Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 1 Nov 2021 16:22:57 +0100 Subject: [PATCH 0843/1244] Keep annotation of @main methods in `def main` Co-authored-by: Guillaume Martres --- compiler/src/dotty/tools/dotc/ast/MainProxies.scala | 12 ++++++++++++ tests/neg-custom-args/no-experimental/i13848.scala | 7 +++++++ tests/pos-custom-args/no-experimental/i13848.scala | 8 ++++++++ 3 files changed, 27 insertions(+) create mode 100644 tests/neg-custom-args/no-experimental/i13848.scala create mode 100644 tests/pos-custom-args/no-experimental/i13848.scala diff --git a/compiler/src/dotty/tools/dotc/ast/MainProxies.scala b/compiler/src/dotty/tools/dotc/ast/MainProxies.scala index 9178478c399b..2eafeca16e39 100644 --- a/compiler/src/dotty/tools/dotc/ast/MainProxies.scala +++ b/compiler/src/dotty/tools/dotc/ast/MainProxies.scala @@ -94,8 +94,20 @@ object MainProxies { val body = Try(call, handler :: Nil, EmptyTree) val mainArg = ValDef(nme.args, TypeTree(defn.ArrayType.appliedTo(defn.StringType)), EmptyTree) .withFlags(Param) + /** Replace typed `Ident`s that have been typed with a TypeSplice with the reference to the symbol. + * The annotations will be retype-checked in another scope that may not have the same imports. + */ + def insertTypeSplices = new TreeMap { + override def transform(tree: Tree)(using Context): Tree = tree match + case tree: tpd.Ident @unchecked => TypedSplice(tree) + case tree => super.transform(tree) + } + val annots = mainFun.annotations + .filterNot(_.matches(defn.MainAnnot)) + .map(annot => insertTypeSplices.transform(annot.tree)) val mainMeth = DefDef(nme.main, (mainArg :: Nil) :: Nil, TypeTree(defn.UnitType), body) .withFlags(JavaStatic) + .withAnnotations(annots) val mainTempl = Template(emptyConstructor, Nil, Nil, EmptyValDef, mainMeth :: Nil) val mainCls = TypeDef(mainFun.name.toTypeName, mainTempl) .withFlags(Final | Invisible) diff --git a/tests/neg-custom-args/no-experimental/i13848.scala b/tests/neg-custom-args/no-experimental/i13848.scala new file mode 100644 index 000000000000..886ab1e85d67 --- /dev/null +++ b/tests/neg-custom-args/no-experimental/i13848.scala @@ -0,0 +1,7 @@ +import annotation.experimental + +@main +def run(): Unit = f // error + +@experimental +def f = 2 diff --git a/tests/pos-custom-args/no-experimental/i13848.scala b/tests/pos-custom-args/no-experimental/i13848.scala new file mode 100644 index 000000000000..8b65ccb078e1 --- /dev/null +++ b/tests/pos-custom-args/no-experimental/i13848.scala @@ -0,0 +1,8 @@ +import annotation.experimental + +@main +@experimental +def run(): Unit = f + +@experimental +def f = 2 From 83584846cad62f2c97c8fc0481ae9cb476415bf2 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Tue, 16 Nov 2021 18:12:58 +0000 Subject: [PATCH 0844/1244] Tighten product match logic in irrefutable check This avoids accidentally considering refutable name-based extractors as irrefutable because they also happen to be a Product. With this change some tests no longer go through the Typ to Prod rewrite that occurs in `minus(a, b)` when `a` is a Typ and `b` is a Prod, leading to a Typ result. This renders in the counter-example as a generic value type rather than a product, which we see in the warning text changes in the tests. Co-authored-by: Gagandeep Kalra Co-authored-by: Mark T. Kennedy --- .../tools/dotc/transform/patmat/Space.scala | 19 ++++++++++--------- .../src/dotty/tools/dotc/typer/Checking.scala | 2 +- tests/patmat/i13737.check | 1 + tests/patmat/i13737.scala | 15 +++++++++++++++ tests/patmat/irrefutable.check | 2 +- 5 files changed, 28 insertions(+), 11 deletions(-) create mode 100644 tests/patmat/i13737.check create mode 100644 tests/patmat/i13737.scala diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index 2bfff0baad6e..45e811e6d91c 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -108,7 +108,7 @@ trait SpaceLogic { def decompose(tp: Type): List[Typ] /** Whether the extractor covers the given type */ - def covers(unapp: TermRef, scrutineeTp: Type): Boolean + def covers(unapp: TermRef, scrutineeTp: Type, argLen: Int): Boolean /** Display space in string format */ def show(sp: Space): String @@ -186,7 +186,7 @@ trait SpaceLogic { isSubType(tp1, tp2) case (Typ(tp1, _), Prod(tp2, fun, ss)) => isSubType(tp1, tp2) - && covers(fun, tp1) + && covers(fun, tp1, ss.length) && isSubspace(Prod(tp2, fun, signature(fun, tp2, ss.length).map(Typ(_, false))), b) case (Prod(_, fun1, ss1), Prod(_, fun2, ss2)) => isSameUnapply(fun1, fun2) && ss1.zip(ss2).forall((isSubspace _).tupled) @@ -240,7 +240,7 @@ trait SpaceLogic { else a case (Typ(tp1, _), Prod(tp2, fun, ss)) => // rationale: every instance of `tp1` is covered by `tp2(_)` - if isSubType(tp1, tp2) && covers(fun, tp1) then + if isSubType(tp1, tp2) && covers(fun, tp1, ss.length) then minus(Prod(tp1, fun, signature(fun, tp1, ss.length).map(Typ(_, false))), b) else if canDecompose(tp1) then tryDecompose1(tp1) @@ -262,6 +262,7 @@ trait SpaceLogic { a case (Prod(tp1, fun1, ss1), Prod(tp2, fun2, ss2)) => if (!isSameUnapply(fun1, fun2)) return a + if (fun1.symbol.name == nme.unapply && ss1.length != ss2.length) return a val range = (0 until ss1.size).toList val cache = Array.fill[Space](ss2.length)(null) @@ -288,13 +289,13 @@ object SpaceEngine { /** Is the unapply or unapplySeq irrefutable? * @param unapp The unapply function reference */ - def isIrrefutable(unapp: TermRef)(using Context): Boolean = { + def isIrrefutable(unapp: TermRef, argLen: Int)(using Context): Boolean = { val unappResult = unapp.widen.finalResultType unappResult.isRef(defn.SomeClass) || unappResult <:< ConstantType(Constant(true)) // only for unapply || (unapp.symbol.is(Synthetic) && unapp.symbol.owner.linkedClass.is(Case)) // scala2 compatibility || unapplySeqTypeElemTp(unappResult).exists // only for unapplySeq - || productArity(unappResult) > 0 + || isProductMatch(unappResult, argLen) || { val isEmptyTp = extractorMemberType(unappResult, nme.isEmpty, NoSourcePosition) isEmptyTp <:< ConstantType(Constant(false)) @@ -304,10 +305,10 @@ object SpaceEngine { /** Is the unapply or unapplySeq irrefutable? * @param unapp The unapply function tree */ - def isIrrefutable(unapp: tpd.Tree)(using Context): Boolean = { + def isIrrefutable(unapp: tpd.Tree, argLen: Int)(using Context): Boolean = { val fun1 = tpd.funPart(unapp) val funRef = fun1.tpe.asInstanceOf[TermRef] - isIrrefutable(funRef) + isIrrefutable(funRef, argLen) } } @@ -606,8 +607,8 @@ class SpaceEngine(using Context) extends SpaceLogic { } /** Whether the extractor covers the given type */ - def covers(unapp: TermRef, scrutineeTp: Type): Boolean = - SpaceEngine.isIrrefutable(unapp) || unapp.symbol == defn.TypeTest_unapply && { + def covers(unapp: TermRef, scrutineeTp: Type, argLen: Int): Boolean = + SpaceEngine.isIrrefutable(unapp, argLen) || unapp.symbol == defn.TypeTest_unapply && { val AppliedType(_, _ :: tp :: Nil) = unapp.prefix.widen.dealias scrutineeTp <:< tp } diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 6343f0bc4716..2b539d54ef49 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -821,7 +821,7 @@ trait Checking { recur(pat1, pt) case UnApply(fn, _, pats) => check(pat, pt) && - (isIrrefutable(fn) || fail(pat, pt)) && { + (isIrrefutable(fn, pats.length) || fail(pat, pt)) && { val argPts = unapplyArgs(fn.tpe.widen.finalResultType, fn, pats, pat.srcPos) pats.corresponds(argPts)(recur) } diff --git a/tests/patmat/i13737.check b/tests/patmat/i13737.check new file mode 100644 index 000000000000..87d5896f5a1a --- /dev/null +++ b/tests/patmat/i13737.check @@ -0,0 +1 @@ +14: Pattern Match Exhaustivity: _: Success diff --git a/tests/patmat/i13737.scala b/tests/patmat/i13737.scala new file mode 100644 index 000000000000..f415e9028334 --- /dev/null +++ b/tests/patmat/i13737.scala @@ -0,0 +1,15 @@ +sealed trait Result + +case class Success(result: String, next: Int) extends Result { + def isEmpty: Boolean = 10 % 2 == 1 + def get: String = result +} + +object Success { + def unapply(x: Success): Success = x +} + +def main = + val res: Result = ??? + res match // error + case Success(v) => v diff --git a/tests/patmat/irrefutable.check b/tests/patmat/irrefutable.check index 383a04115664..3d07c35a5502 100644 --- a/tests/patmat/irrefutable.check +++ b/tests/patmat/irrefutable.check @@ -1,2 +1,2 @@ 22: Pattern Match Exhaustivity: _: A, _: B, C(_, _) -65: Pattern Match Exhaustivity: ExM(_, _) +65: Pattern Match Exhaustivity: _: M From 2dee22d5dc04b930cf68d7322ed9b9daf38b0cb2 Mon Sep 17 00:00:00 2001 From: Jakob Odersky Date: Mon, 15 Nov 2021 12:31:52 +0100 Subject: [PATCH 0845/1244] Initialize quote cache on tasty run This fixes #13919 --- .../sbt-dotty/tasty-inspector-cache/build.sbt | 24 +++++++++++++++++++ .../inspector/src/main/scala/main.scala | 14 +++++++++++ .../lib/src/main/scala/dummy.scala | 1 + sbt-test/sbt-dotty/tasty-inspector-cache/test | 1 + .../tasty/inspector/TastyInspector.scala | 7 +++++- 5 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 sbt-test/sbt-dotty/tasty-inspector-cache/build.sbt create mode 100644 sbt-test/sbt-dotty/tasty-inspector-cache/inspector/src/main/scala/main.scala create mode 100644 sbt-test/sbt-dotty/tasty-inspector-cache/lib/src/main/scala/dummy.scala create mode 100644 sbt-test/sbt-dotty/tasty-inspector-cache/test diff --git a/sbt-test/sbt-dotty/tasty-inspector-cache/build.sbt b/sbt-test/sbt-dotty/tasty-inspector-cache/build.sbt new file mode 100644 index 000000000000..3bece1b43fa7 --- /dev/null +++ b/sbt-test/sbt-dotty/tasty-inspector-cache/build.sbt @@ -0,0 +1,24 @@ +lazy val dottyVersion = sys.props("plugin.scalaVersion") + +lazy val lib = project + .in(file("lib")) + .settings( + scalaVersion := dottyVersion + ) + +val jarDest = file("target") / "app.jar" + +val runTest = Def.taskKey[Unit]("run tests") + +lazy val inspector = project + .in(file("inspector")) + .settings( + scalaVersion := dottyVersion, + libraryDependencies += "org.scala-lang" %% "scala3-tasty-inspector" % scalaVersion.value, + runTest := + Def.sequential( + Def.task(IO.copyFile((lib/Compile/packageBin).value, jarDest)), + (Compile/run).toTask(" " + jarDest.getAbsolutePath) + ).value + ) + .dependsOn(lib) diff --git a/sbt-test/sbt-dotty/tasty-inspector-cache/inspector/src/main/scala/main.scala b/sbt-test/sbt-dotty/tasty-inspector-cache/inspector/src/main/scala/main.scala new file mode 100644 index 000000000000..8335a016578f --- /dev/null +++ b/sbt-test/sbt-dotty/tasty-inspector-cache/inspector/src/main/scala/main.scala @@ -0,0 +1,14 @@ +import scala.quoted.Quotes +import scala.quoted.quotes +import scala.tasty.inspector as ins + +// Test for https://github.com/lampepfl/dotty/issues/13919 +class MyInspector extends ins.Inspector: + def inspect(using Quotes)(tastys: List[ins.Tasty[quotes.type]]): Unit = + import quotes.reflect._ + TypeRepr.of[Int] + TypeRepr.of[String] + + +@main def main(args: String*): Unit = + ins.TastyInspector.inspectTastyFilesInJar(args.head)(new MyInspector) diff --git a/sbt-test/sbt-dotty/tasty-inspector-cache/lib/src/main/scala/dummy.scala b/sbt-test/sbt-dotty/tasty-inspector-cache/lib/src/main/scala/dummy.scala new file mode 100644 index 000000000000..52d946a2a65d --- /dev/null +++ b/sbt-test/sbt-dotty/tasty-inspector-cache/lib/src/main/scala/dummy.scala @@ -0,0 +1 @@ +class Dummy // we need at least one file for the tasty inspector to run diff --git a/sbt-test/sbt-dotty/tasty-inspector-cache/test b/sbt-test/sbt-dotty/tasty-inspector-cache/test new file mode 100644 index 000000000000..8fa783e886e2 --- /dev/null +++ b/sbt-test/sbt-dotty/tasty-inspector-cache/test @@ -0,0 +1 @@ +> inspector/runTest diff --git a/tasty-inspector/src/scala/tasty/inspector/TastyInspector.scala b/tasty-inspector/src/scala/tasty/inspector/TastyInspector.scala index ab3f3e86357f..4c6440530ba2 100644 --- a/tasty-inspector/src/scala/tasty/inspector/TastyInspector.scala +++ b/tasty-inspector/src/scala/tasty/inspector/TastyInspector.scala @@ -10,6 +10,7 @@ import dotty.tools.dotc.core.Contexts.Context import dotty.tools.dotc.core.Mode import dotty.tools.dotc.core.Phases.Phase import dotty.tools.dotc.fromtasty._ +import dotty.tools.dotc.quoted.QuotesCache import dotty.tools.dotc.util.ClasspathFromClassloader import dotty.tools.dotc.CompilationUnit import dotty.tools.unsupported @@ -64,7 +65,11 @@ object TastyInspector: class TastyInspectorPhase extends Phase: override def phaseName: String = "tastyInspector" - override def runOn(units: List[CompilationUnit])(using Context): List[CompilationUnit] = + override def runOn(units: List[CompilationUnit])(using ctx0: Context): List[CompilationUnit] = + val ctx = QuotesCache.init(ctx0.fresh) + runOnImpl(units)(using ctx) + + private def runOnImpl(units: List[CompilationUnit])(using Context): List[CompilationUnit] = val quotesImpl = QuotesImpl() class TastyImpl(val path: String, val ast: quotesImpl.reflect.Tree) extends Tasty[quotesImpl.type] { val quotes = quotesImpl From 1b1dbd35931b8be227ecc1152ef4705c9db05d79 Mon Sep 17 00:00:00 2001 From: Rikito Taniguchi Date: Mon, 6 Sep 2021 18:08:49 +0900 Subject: [PATCH 0846/1244] Support TypeApplication in Synthetic --- .../dotc/semanticdb/ExtractSemanticDB.scala | 5 + .../dotc/semanticdb/SyntheticsExtractor.scala | 48 ++++++- tests/semanticdb/metac.expect | 130 +++++++++++++++++- 3 files changed, 175 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala index 086c844e9d03..3c2c08ded7a0 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala @@ -251,6 +251,11 @@ class ExtractSemanticDB extends Phase: case tree: Inlined => traverse(tree.call) + + case tree: TypeApply => + synth.tryFindSynthetic(tree).foreach(synthetics.addOne) + traverseChildren(tree) + case tree: TypeTree => tree.typeOpt match // Any types could be appear inside of `TypeTree`, but diff --git a/compiler/src/dotty/tools/dotc/semanticdb/SyntheticsExtractor.scala b/compiler/src/dotty/tools/dotc/semanticdb/SyntheticsExtractor.scala index c6d87c67a578..0818b7cf1be1 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/SyntheticsExtractor.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/SyntheticsExtractor.scala @@ -11,14 +11,44 @@ import scala.collection.mutable class SyntheticsExtractor: import Scala3.{_, given} + val visited = collection.mutable.HashSet[Tree]() + def tryFindSynthetic(tree: Tree)(using Context, SemanticSymbolBuilder, TypeOps): Option[s.Synthetic] = extension (synth: s.Synthetic) def toOpt: Some[s.Synthetic] = Some(synth) - if tree.span.isSynthetic then + val forSynthetic = tree match // not yet supported (for synthetics) + case tree: Apply if isForSynthetic(tree) => true + case tree: TypeApply if isForSynthetic(tree) => true + case _ => false + + if visited.contains(tree) || forSynthetic then None + else tree match - case tree: Apply if isForSynthetic(tree) => - None // not yet supported (for synthetics) + case tree: TypeApply + if tree.span.isSynthetic && + tree.args.forall(arg => !arg.symbol.is(Scala2x)) && + !tree.span.isZeroExtent => + visited.add(tree) + val fnTree = tree.fun match + // Something like `List.apply[Int](1,2,3)` + case select @ Select(qual, _) if isSyntheticName(select) => + s.SelectTree( + s.OriginalTree(range(qual.span, tree.source)), + Some(select.toSemanticId) + ) + case _ => + s.OriginalTree( + range(tree.fun.span, tree.source) + ) + val targs = tree.args.map(targ => targ.tpe.toSemanticType(targ.symbol)(using LinkMode.SymlinkChildren)) + s.Synthetic( + range(tree.span, tree.source), + s.TypeApplyTree( + fnTree, targs + ) + ).toOpt + case tree: Apply if tree.args.nonEmpty && tree.args.forall(arg => @@ -46,7 +76,6 @@ class SyntheticsExtractor: ).toOpt case _ => None - else None private given TreeOps: AnyRef with extension (tree: Tree) @@ -95,4 +124,15 @@ class SyntheticsExtractor: case select: Select => isForComprehensionSyntheticName(select) case _ => false + private def isSyntheticName(select: Select): Boolean = + select.span.toSynthetic == select.qualifier.span.toSynthetic && ( + select.name == nme.apply || + select.name == nme.update || + select.name == nme.foreach || + select.name == nme.withFilter || + select.name == nme.flatMap || + select.name == nme.map || + select.name == nme.unapplySeq || + select.name == nme.unapply) + end SyntheticsExtractor diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index 07b3174b3d93..732e9b07aa85 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -224,6 +224,7 @@ Text => empty Language => Scala Symbols => 23 entries Occurrences => 52 entries +Synthetics => 2 entries Symbols: annot/Alias. => final object Alias extends Object { self: Alias.type => +2 decls } @@ -304,6 +305,10 @@ Occurrences: [39:11..39:26): ClassAnnotation -> com/javacp/annot/ClassAnnotation# [39:28..39:33): param -> scala/annotation/meta/param# +Synthetics: +[25:2..25:20):@throws[Exception] => *[Exception] +[25:2..25:20):@throws[Exception] => *[Exception] + expect/Anonymous.scala ---------------------- @@ -314,6 +319,7 @@ Text => empty Language => Scala Symbols => 14 entries Occurrences => 30 entries +Synthetics => 2 entries Symbols: example/Anonymous# => class Anonymous extends Object { self: Anonymous & Anonymous => +6 decls } @@ -363,6 +369,10 @@ Occurrences: [18:6..18:9): foo <- example/Anonymous#foo. [18:16..18:19): Foo -> example/Anonymous#Foo# +Synthetics: +[10:2..10:9):locally => *[Unit] +[13:2..13:9):locally => *[Unit] + expect/AnonymousGiven.scala --------------------------- @@ -397,6 +407,7 @@ Text => empty Language => Scala Symbols => 109 entries Occurrences => 113 entries +Synthetics => 2 entries Symbols: classes/C1# => final class C1 extends AnyVal { self: C1 => +2 decls } @@ -624,6 +635,10 @@ Occurrences: [53:4..53:9): local -> local4 [53:10..53:11): + -> scala/Int#`+`(+4). +Synthetics: +[51:16..51:27):List(1).map => *[Int] +[51:16..51:20):List => *.apply[Int] + expect/Empty.scala ------------------ @@ -826,6 +841,7 @@ Text => empty Language => Scala Symbols => 181 entries Occurrences => 148 entries +Synthetics => 10 entries Symbols: _empty_/Enums. => final object Enums extends Object { self: Enums.type => +30 decls } @@ -1160,6 +1176,18 @@ Occurrences: [68:9..68:16): Neptune <- _empty_/Enums.Planet.Neptune. [68:25..68:31): Planet -> _empty_/Enums.Planet# +Synthetics: +[46:28..46:35):C <:< C => *[C, C] +[49:27..49:31):Refl => *.apply[T] +[52:9..52:13):Refl => *.unapply[Option[B]] +[52:19..52:30):opt.flatMap => *[B] +[52:31..52:50):identity[Option[B]] => *[Function1[A, Option[B]]] +[54:14..54:18):Some => *.apply[Some[Int]] +[54:14..54:34):Some(Some(1)).unwrap => *(given_<:<_T_T[Option[Int]]) +[54:19..54:23):Some => *.apply[Int] +[54:28..54:34):unwrap => *[Some[Int], Int] +[56:52..56:64):Enum[Planet] => *[Planet] + expect/EtaExpansion.scala ------------------------- @@ -1170,6 +1198,7 @@ Text => empty Language => Scala Symbols => 3 entries Occurrences => 8 entries +Synthetics => 5 entries Symbols: example/EtaExpansion# => class EtaExpansion extends Object { self: EtaExpansion => +1 decls } @@ -1186,6 +1215,13 @@ Occurrences: [4:10..4:18): foldLeft -> scala/collection/LinearSeqOps#foldLeft(). [4:25..4:26): + -> java/lang/String#`+`(). +Synthetics: +[3:2..3:13):Some(1).map => *[Int] +[3:2..3:6):Some => *.apply[Int] +[3:14..3:22):identity => *[Int] +[4:2..4:18):List(1).foldLeft => *[String] +[4:2..4:6):List => *.apply[Int] + expect/Example.scala -------------------- @@ -1334,6 +1370,7 @@ Text => empty Language => Scala Symbols => 13 entries Occurrences => 52 entries +Synthetics => 6 entries Symbols: example/ForComprehension# => class ForComprehension extends Object { self: ForComprehension => +1 decls } @@ -1404,6 +1441,14 @@ Occurrences: [40:6..40:7): e -> local9 [41:6..41:7): f -> local10 +Synthetics: +[4:9..4:13):List => *.apply[Int] +[5:9..5:13):List => *.apply[Int] +[10:9..10:13):List => *.apply[Int] +[11:9..11:13):List => *.apply[Int] +[19:9..19:13):List => *.apply[Tuple2[Int, Int]] +[33:9..33:13):List => *.apply[Tuple4[Int, Int, Int, Int]] + expect/Givens.scala ------------------- @@ -1414,6 +1459,7 @@ Text => empty Language => Scala Symbols => 29 entries Occurrences => 65 entries +Synthetics => 3 entries Symbols: a/b/Givens. => final object Givens extends Object { self: Givens.type => +12 decls } @@ -1513,6 +1559,11 @@ Occurrences: [26:57..26:58): A -> a/b/Givens.foo().(A) [26:59..26:64): empty -> a/b/Givens.Monoid#empty(). +Synthetics: +[12:17..12:25):sayHello => *[Int] +[13:19..13:29):sayGoodbye => *[Int] +[14:18..14:27):saySoLong => *[Int] + expect/ImplicitConversion.scala ------------------------------- @@ -1655,6 +1706,7 @@ Text => empty Language => Scala Symbols => 8 entries Occurrences => 52 entries +Synthetics => 2 entries Symbols: example/InstrumentTyper# => class InstrumentTyper extends Object { self: AnyRef & InstrumentTyper => +5 decls } @@ -1720,6 +1772,10 @@ Occurrences: [24:30..24:36): Option -> scala/Option# [24:37..24:40): Int -> scala/Int# +Synthetics: +[8:12..8:16):List => *.apply[Matchable] +[20:4..20:8):List => *.apply[Nothing] + expect/InventedNames.scala -------------------------- @@ -1907,6 +1963,7 @@ Text => empty Language => Scala Symbols => 6 entries Occurrences => 10 entries +Synthetics => 1 entries Symbols: example/Local# => class Local extends Object { self: Local => +2 decls } @@ -1928,6 +1985,9 @@ Occurrences: [4:25..4:26): a -> local1 [5:4..5:6): id -> local2 +Synthetics: +[5:4..5:6):id => *[Int] + expect/Locals.scala ------------------- @@ -1938,6 +1998,7 @@ Text => empty Language => Scala Symbols => 3 entries Occurrences => 6 entries +Synthetics => 1 entries Symbols: local0 => val local x: Int @@ -1952,6 +2013,9 @@ Occurrences: [5:4..5:8): List -> scala/package.List. [5:9..5:10): x -> local0 +Synthetics: +[5:4..5:8):List => *.apply[Int] + expect/MetacJava.scala ---------------------- @@ -2049,7 +2113,7 @@ Text => empty Language => Scala Symbols => 3 entries Occurrences => 80 entries -Synthetics => 1 entries +Synthetics => 2 entries Symbols: example/MethodUsages# => class MethodUsages extends Object { self: MethodUsages => +2 decls } @@ -2139,6 +2203,7 @@ Occurrences: [34:8..34:9): m -> example/Methods#m17.m(). Synthetics: +[13:2..13:6):m.m7 => *[Int] [13:2..13:26):m.m7(m, new m.List[Int]) => *(Int) expect/Methods.scala @@ -2715,7 +2780,7 @@ Text => empty Language => Scala Symbols => 68 entries Occurrences => 110 entries -Synthetics => 1 entries +Synthetics => 3 entries Symbols: example/C# => class C extends Object { self: C => +3 decls } @@ -2900,7 +2965,9 @@ Occurrences: [32:57..32:59): as -> example/PickOneRefinement_1#run().(as) Synthetics: +[15:23..15:34):elems.toMap => *[String, Any] [15:23..15:34):elems.toMap => *(refl[Tuple2[String, Any]]) +[32:47..32:56):s.pickOne => *[String] expect/RightAssociativeExtension.scala -------------------------------------- @@ -2989,7 +3056,7 @@ Text => empty Language => Scala Symbols => 52 entries Occurrences => 132 entries -Synthetics => 21 entries +Synthetics => 36 entries Symbols: example/Synthetic# => class Synthetic extends Object { self: Synthetic => +23 decls } @@ -3180,15 +3247,26 @@ Occurrences: [58:6..58:9): foo -> example/Synthetic#Contexts.foo(). Synthetics: +[5:2..5:13):List(1).map => *[Int] +[5:2..5:6):List => *.apply[Int] [6:2..6:18):Array.empty[Int] => intArrayOps(*) [7:2..7:8):"fooo" => augmentString(*) [10:13..10:24):"name:(.*)" => augmentString(*) +[11:17..11:25):LazyList => *.apply[Int] +[13:4..13:28):#:: 2 #:: LazyList.empty => *[Int] [13:8..13:28):2 #:: LazyList.empty => toDeferrer[Int](*) +[13:10..13:28):#:: LazyList.empty => *[Int] [13:14..13:28):LazyList.empty => toDeferrer[Nothing](*) +[13:14..13:28):LazyList.empty => *[Nothing] +[15:25..15:33):LazyList => *.apply[Int] +[17:14..17:38):#:: 2 #:: LazyList.empty => *[Int] [17:18..17:38):2 #:: LazyList.empty => toDeferrer[Int](*) +[17:20..17:38):#:: LazyList.empty => *[Int] [17:24..17:38):LazyList.empty => toDeferrer[Nothing](*) +[17:24..17:38):LazyList.empty => *[Nothing] [19:12..19:13):1 => intWrapper(*) [19:26..19:27):0 => intWrapper(*) +[19:46..19:50):x -> => *[Int] [19:46..19:47):x => ArrowAssoc[Int](*) [20:12..20:13):1 => intWrapper(*) [20:26..20:27):0 => intWrapper(*) @@ -3197,6 +3275,10 @@ Synthetics: [32:35..32:49):Array.empty[T] => *(evidence$1) [36:22..36:27):new F => orderingToOrdered[F](*) [36:22..36:27):new F => *(ordering) +[40:9..40:43):scala.concurrent.Future.successful => *[Int] +[41:9..41:43):scala.concurrent.Future.successful => *[Int] +[44:9..44:43):scala.concurrent.Future.successful => *[Int] +[45:9..45:43):scala.concurrent.Future.successful => *[Int] [51:24..51:30):foo(0) => *(x$1) [52:27..52:33):foo(0) => *(x) [55:6..55:12):foo(x) => *(x) @@ -3252,6 +3334,7 @@ Text => empty Language => Scala Symbols => 22 entries Occurrences => 46 entries +Synthetics => 7 entries Symbols: example/ValPattern# => class ValPattern extends Object { self: ValPattern => +14 decls } @@ -3325,6 +3408,15 @@ Occurrences: [39:10..39:17): leftVar -> local3 [40:10..40:18): rightVar -> local4 +Synthetics: +[6:4..6:8):Some => *.apply[Int] +[8:6..8:10):List => *.unapplySeq[Nothing] +[8:11..8:15):Some => *.unapply[Nothing] +[12:4..12:8):Some => *.apply[Int] +[25:4..25:11):locally => *[Unit] +[28:8..28:12):Some => *.apply[Int] +[32:8..32:12):Some => *.apply[Int] + expect/Vals.scala ----------------- @@ -3845,6 +3937,7 @@ Text => empty Language => Scala Symbols => 3 entries Occurrences => 6 entries +Synthetics => 1 entries Symbols: example/`local-file`# => class local-file extends Object { self: local-file => +1 decls } @@ -3859,6 +3952,9 @@ Occurrences: [5:4..5:9): local -> local0 [5:10..5:11): + -> scala/Int#`+`(+4). +Synthetics: +[3:2..3:9):locally => *[Int] + expect/nullary.scala -------------------- @@ -3869,6 +3965,7 @@ Text => empty Language => Scala Symbols => 17 entries Occurrences => 29 entries +Synthetics => 1 entries Symbols: _empty_/Concrete# => class Concrete extends NullaryTest[Int, List] { self: Concrete => +3 decls } @@ -3920,6 +4017,9 @@ Occurrences: [18:7..18:15): Concrete -> _empty_/Concrete# [18:17..18:25): nullary3 -> _empty_/Concrete#nullary3(). +Synthetics: +[13:17..13:21):List => *.apply[Int] + expect/recursion.scala ---------------------- @@ -3930,6 +4030,7 @@ Text => empty Language => Scala Symbols => 36 entries Occurrences => 46 entries +Synthetics => 3 entries Symbols: local0 => case val method N$1 <: Nat @@ -4017,6 +4118,11 @@ Occurrences: [23:35..23:39): Zero -> recursion/Nats.Zero. [23:40..23:42): ++ -> recursion/Nats.Nat#`++`(). +Synthetics: +[5:50..5:54):Succ => *.apply[Nat.this.type] +[10:13..10:17):Succ => *.unapply[N$1] +[20:11..20:15):Succ => *.unapply[N$2] + expect/semanticdb-Definitions.scala ----------------------------------- @@ -4059,6 +4165,7 @@ Text => empty Language => Scala Symbols => 50 entries Occurrences => 73 entries +Synthetics => 2 entries Symbols: flags/p/package. => final package object p extends Object { self: p.type => +23 decls } @@ -4187,6 +4294,10 @@ Occurrences: [25:27..25:28): t <- local1 [25:33..25:36): ??? -> scala/Predef.`???`(). +Synthetics: +[23:6..23:10):List => *.unapplySeq[Nothing] +[24:19..24:23):List => *.unapplySeq[Nothing] + expect/semanticdb-Types.scala ----------------------------- @@ -4197,6 +4308,7 @@ Text => empty Language => Scala Symbols => 144 entries Occurrences => 225 entries +Synthetics => 1 entries Symbols: local0 => abstract method k => Int @@ -4571,6 +4683,9 @@ Occurrences: [119:32..119:38): Option -> scala/Option# [119:39..119:42): Int -> scala/Int# +Synthetics: +[68:20..68:24):@ann => *[Int] + expect/semanticdb-extract.scala ------------------------------- @@ -4581,6 +4696,7 @@ Text => empty Language => Scala Symbols => 18 entries Occurrences => 20 entries +Synthetics => 3 entries Symbols: _empty_/AnObject. => final object AnObject extends Object { self: AnObject.type => +6 decls } @@ -4624,6 +4740,11 @@ Occurrences: [16:17..16:18): x <- _empty_/AnObject.Foo#x. [16:20..16:23): Int -> scala/Int# +Synthetics: +[11:2..11:6):List => *.apply[Int] +[12:2..12:12):List.apply => *[Nothing] +[13:2..13:14):List.`apply` => *[Nothing] + expect/toplevel.scala --------------------- @@ -4634,7 +4755,7 @@ Text => empty Language => Scala Symbols => 18 entries Occurrences => 43 entries -Synthetics => 1 entries +Synthetics => 2 entries Symbols: _empty_/MyProgram# => final class MyProgram extends Object { self: MyProgram => +2 decls } @@ -4702,5 +4823,6 @@ Occurrences: [7:30..7:33): foo -> _empty_/toplevel$package.foo(). Synthetics: +[5:40..5:60):(1 to times) foreach => *[Unit] [5:41..5:42):1 => intWrapper(*) From b23c9ac667d9020d764a9305c8cfdc516d965439 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 22 Nov 2021 10:33:23 +0100 Subject: [PATCH 0847/1244] Use `inline val` for inlined `final val`s These `val`s are already inlined and do not generate a field, but they still generate a getter that is never used. My marking these as `inline` we can remove the getter and save a few bytes at runtime. By making these fields `inline` we can also check that the RHS constant folds to a value at compile time. --- .../tools/backend/ScalaPrimitivesOps.scala | 262 ++++---- .../dotty/tools/backend/jvm/AsmUtils.scala | 8 +- .../tools/backend/jvm/BCodeSkelBuilder.scala | 2 +- .../dotty/tools/backend/sjs/JSCodeGen.scala | 2 +- .../tools/backend/sjs/JSPrimitives.scala | 50 +- .../src/dotty/tools/dotc/core/Constants.scala | 26 +- .../dotty/tools/dotc/core/Decorators.scala | 2 +- .../src/dotty/tools/dotc/core/Hashable.scala | 8 +- .../src/dotty/tools/dotc/core/NameOps.scala | 2 +- .../src/dotty/tools/dotc/core/NameTags.scala | 22 +- .../src/dotty/tools/dotc/core/Periods.scala | 18 +- .../src/dotty/tools/dotc/core/Scopes.scala | 6 +- .../src/dotty/tools/dotc/core/StdNames.scala | 54 +- .../core/classfile/ClassfileConstants.scala | 570 +++++++++--------- .../tools/dotc/core/tasty/TreeBuffer.scala | 2 +- .../tools/dotc/core/tasty/TreeUnpickler.scala | 6 +- .../core/unpickleScala2/PickleBuffer.scala | 6 +- .../core/unpickleScala2/PickleFormat.scala | 190 +++--- .../core/unpickleScala2/Scala2Flags.scala | 140 ++--- .../dotty/tools/dotc/parsing/JavaTokens.scala | 130 ++-- .../src/dotty/tools/dotc/parsing/Tokens.scala | 252 ++++---- .../dotc/printing/SyntaxHighlighting.scala | 2 +- .../tools/dotc/transform/PatternMatcher.scala | 4 +- .../dotc/transform/sjs/JSExportUtils.scala | 6 +- .../dotty/tools/dotc/typer/Implicits.scala | 8 +- .../src/dotty/tools/dotc/util/Chars.scala | 8 +- .../tools/dotc/util/ReusableInstance.scala | 2 +- .../tools/dotc/util/SixteenNibbles.scala | 4 +- .../src/dotty/tools/dotc/util/Spans.scala | 6 +- .../src/dotty/tools/dotc/util/Stats.scala | 4 +- 30 files changed, 901 insertions(+), 901 deletions(-) diff --git a/compiler/src/dotty/tools/backend/ScalaPrimitivesOps.scala b/compiler/src/dotty/tools/backend/ScalaPrimitivesOps.scala index 40b567b640b8..6b5bfbc3e00e 100644 --- a/compiler/src/dotty/tools/backend/ScalaPrimitivesOps.scala +++ b/compiler/src/dotty/tools/backend/ScalaPrimitivesOps.scala @@ -5,161 +5,161 @@ object ScalaPrimitivesOps extends ScalaPrimitivesOps class ScalaPrimitivesOps { // Arithmetic unary operations - final val POS = 1 // +x - final val NEG = 2 // -x - final val NOT = 3 // ~x + inline val POS = 1 // +x + inline val NEG = 2 // -x + inline val NOT = 3 // ~x // Arithmetic binary operations - final val ADD = 10 // x + y - final val SUB = 11 // x - y - final val MUL = 12 // x * y - final val DIV = 13 // x / y - final val MOD = 14 // x % y + inline val ADD = 10 // x + y + inline val SUB = 11 // x - y + inline val MUL = 12 // x * y + inline val DIV = 13 // x / y + inline val MOD = 14 // x % y // Bitwise operations - final val OR = 20 // x | y - final val XOR = 21 // x ^ y - final val AND = 22 // x & y + inline val OR = 20 // x | y + inline val XOR = 21 // x ^ y + inline val AND = 22 // x & y // Shift operations - final val LSL = 30 // x << y - final val LSR = 31 // x >>> y - final val ASR = 32 // x >> y + inline val LSL = 30 // x << y + inline val LSR = 31 // x >>> y + inline val ASR = 32 // x >> y // Comparison operations - final val ID = 40 // x eq y - final val NI = 41 // x ne y - final val EQ = 42 // x == y - final val NE = 43 // x != y - final val LT = 44 // x < y - final val LE = 45 // x <= y - final val GT = 46 // x > y - final val GE = 47 // x >= y + inline val ID = 40 // x eq y + inline val NI = 41 // x ne y + inline val EQ = 42 // x == y + inline val NE = 43 // x != y + inline val LT = 44 // x < y + inline val LE = 45 // x <= y + inline val GT = 46 // x > y + inline val GE = 47 // x >= y // Boolean unary operations - final val ZNOT = 50 // !x + inline val ZNOT = 50 // !x // Boolean binary operations - final val ZOR = 60 // x || y - final val ZAND = 61 // x && y + inline val ZOR = 60 // x || y + inline val ZAND = 61 // x && y // Array operations - final val LENGTH = 70 // x.length - final val APPLY = 71 // x(y) - final val UPDATE = 72 // x(y) = z + inline val LENGTH = 70 // x.length + inline val APPLY = 71 // x(y) + inline val UPDATE = 72 // x(y) = z // Any operations - final val IS = 80 // x.is[y] - final val AS = 81 // x.as[y] - final val HASH = 87 // x.## + inline val IS = 80 // x.is[y] + inline val AS = 81 // x.as[y] + inline val HASH = 87 // x.## // AnyRef operations - final val SYNCHRONIZED = 90 // x.synchronized(y) + inline val SYNCHRONIZED = 90 // x.synchronized(y) // String operations - final val CONCAT = 100 // String.valueOf(x)+String.valueOf(y) + inline val CONCAT = 100 // String.valueOf(x)+String.valueOf(y) // coercions - final val COERCE = 101 + inline val COERCE = 101 // RunTime operations - final val BOX = 110 // RunTime.box_(x) - final val UNBOX = 111 // RunTime.unbox_(x) - final val NEW_ZARRAY = 112 // RunTime.zarray(x) - final val NEW_BARRAY = 113 // RunTime.barray(x) - final val NEW_SARRAY = 114 // RunTime.sarray(x) - final val NEW_CARRAY = 115 // RunTime.carray(x) - final val NEW_IARRAY = 116 // RunTime.iarray(x) - final val NEW_LARRAY = 117 // RunTime.larray(x) - final val NEW_FARRAY = 118 // RunTime.farray(x) - final val NEW_DARRAY = 119 // RunTime.darray(x) - final val NEW_OARRAY = 120 // RunTime.oarray(x) - - final val ZARRAY_LENGTH = 131 // RunTime.zarray_length(x) - final val BARRAY_LENGTH = 132 // RunTime.barray_length(x) - final val SARRAY_LENGTH = 133 // RunTime.sarray_length(x) - final val CARRAY_LENGTH = 134 // RunTime.carray_length(x) - final val IARRAY_LENGTH = 135 // RunTime.iarray_length(x) - final val LARRAY_LENGTH = 136 // RunTime.larray_length(x) - final val FARRAY_LENGTH = 137 // RunTime.farray_length(x) - final val DARRAY_LENGTH = 138 // RunTime.darray_length(x) - final val OARRAY_LENGTH = 139 // RunTime.oarray_length(x) - - final val ZARRAY_GET = 140 // RunTime.zarray_get(x,y) - final val BARRAY_GET = 141 // RunTime.barray_get(x,y) - final val SARRAY_GET = 142 // RunTime.sarray_get(x,y) - final val CARRAY_GET = 143 // RunTime.carray_get(x,y) - final val IARRAY_GET = 144 // RunTime.iarray_get(x,y) - final val LARRAY_GET = 145 // RunTime.larray_get(x,y) - final val FARRAY_GET = 146 // RunTime.farray_get(x,y) - final val DARRAY_GET = 147 // RunTime.darray_get(x,y) - final val OARRAY_GET = 148 // RunTime.oarray_get(x,y) - - final val ZARRAY_SET = 150 // RunTime.zarray(x,y,z) - final val BARRAY_SET = 151 // RunTime.barray(x,y,z) - final val SARRAY_SET = 152 // RunTime.sarray(x,y,z) - final val CARRAY_SET = 153 // RunTime.carray(x,y,z) - final val IARRAY_SET = 154 // RunTime.iarray(x,y,z) - final val LARRAY_SET = 155 // RunTime.larray(x,y,z) - final val FARRAY_SET = 156 // RunTime.farray(x,y,z) - final val DARRAY_SET = 157 // RunTime.darray(x,y,z) - final val OARRAY_SET = 158 // RunTime.oarray(x,y,z) - - final val B2B = 200 // RunTime.b2b(x) - final val B2S = 201 // RunTime.b2s(x) - final val B2C = 202 // RunTime.b2c(x) - final val B2I = 203 // RunTime.b2i(x) - final val B2L = 204 // RunTime.b2l(x) - final val B2F = 205 // RunTime.b2f(x) - final val B2D = 206 // RunTime.b2d(x) - - final val S2B = 210 // RunTime.s2b(x) - final val S2S = 211 // RunTime.s2s(x) - final val S2C = 212 // RunTime.s2c(x) - final val S2I = 213 // RunTime.s2i(x) - final val S2L = 214 // RunTime.s2l(x) - final val S2F = 215 // RunTime.s2f(x) - final val S2D = 216 // RunTime.s2d(x) - - final val C2B = 220 // RunTime.c2b(x) - final val C2S = 221 // RunTime.c2s(x) - final val C2C = 222 // RunTime.c2c(x) - final val C2I = 223 // RunTime.c2i(x) - final val C2L = 224 // RunTime.c2l(x) - final val C2F = 225 // RunTime.c2f(x) - final val C2D = 226 // RunTime.c2d(x) - - final val I2B = 230 // RunTime.i2b(x) - final val I2S = 231 // RunTime.i2s(x) - final val I2C = 232 // RunTime.i2c(x) - final val I2I = 233 // RunTime.i2i(x) - final val I2L = 234 // RunTime.i2l(x) - final val I2F = 235 // RunTime.i2f(x) - final val I2D = 236 // RunTime.i2d(x) - - final val L2B = 240 // RunTime.l2b(x) - final val L2S = 241 // RunTime.l2s(x) - final val L2C = 242 // RunTime.l2c(x) - final val L2I = 243 // RunTime.l2i(x) - final val L2L = 244 // RunTime.l2l(x) - final val L2F = 245 // RunTime.l2f(x) - final val L2D = 246 // RunTime.l2d(x) - - final val F2B = 250 // RunTime.f2b(x) - final val F2S = 251 // RunTime.f2s(x) - final val F2C = 252 // RunTime.f2c(x) - final val F2I = 253 // RunTime.f2i(x) - final val F2L = 254 // RunTime.f2l(x) - final val F2F = 255 // RunTime.f2f(x) - final val F2D = 256 // RunTime.f2d(x) - - final val D2B = 260 // RunTime.d2b(x) - final val D2S = 261 // RunTime.d2s(x) - final val D2C = 262 // RunTime.d2c(x) - final val D2I = 263 // RunTime.d2i(x) - final val D2L = 264 // RunTime.d2l(x) - final val D2F = 265 // RunTime.d2f(x) - final val D2D = 266 // RunTime.d2d(x) + inline val BOX = 110 // RunTime.box_(x) + inline val UNBOX = 111 // RunTime.unbox_(x) + inline val NEW_ZARRAY = 112 // RunTime.zarray(x) + inline val NEW_BARRAY = 113 // RunTime.barray(x) + inline val NEW_SARRAY = 114 // RunTime.sarray(x) + inline val NEW_CARRAY = 115 // RunTime.carray(x) + inline val NEW_IARRAY = 116 // RunTime.iarray(x) + inline val NEW_LARRAY = 117 // RunTime.larray(x) + inline val NEW_FARRAY = 118 // RunTime.farray(x) + inline val NEW_DARRAY = 119 // RunTime.darray(x) + inline val NEW_OARRAY = 120 // RunTime.oarray(x) + + inline val ZARRAY_LENGTH = 131 // RunTime.zarray_length(x) + inline val BARRAY_LENGTH = 132 // RunTime.barray_length(x) + inline val SARRAY_LENGTH = 133 // RunTime.sarray_length(x) + inline val CARRAY_LENGTH = 134 // RunTime.carray_length(x) + inline val IARRAY_LENGTH = 135 // RunTime.iarray_length(x) + inline val LARRAY_LENGTH = 136 // RunTime.larray_length(x) + inline val FARRAY_LENGTH = 137 // RunTime.farray_length(x) + inline val DARRAY_LENGTH = 138 // RunTime.darray_length(x) + inline val OARRAY_LENGTH = 139 // RunTime.oarray_length(x) + + inline val ZARRAY_GET = 140 // RunTime.zarray_get(x,y) + inline val BARRAY_GET = 141 // RunTime.barray_get(x,y) + inline val SARRAY_GET = 142 // RunTime.sarray_get(x,y) + inline val CARRAY_GET = 143 // RunTime.carray_get(x,y) + inline val IARRAY_GET = 144 // RunTime.iarray_get(x,y) + inline val LARRAY_GET = 145 // RunTime.larray_get(x,y) + inline val FARRAY_GET = 146 // RunTime.farray_get(x,y) + inline val DARRAY_GET = 147 // RunTime.darray_get(x,y) + inline val OARRAY_GET = 148 // RunTime.oarray_get(x,y) + + inline val ZARRAY_SET = 150 // RunTime.zarray(x,y,z) + inline val BARRAY_SET = 151 // RunTime.barray(x,y,z) + inline val SARRAY_SET = 152 // RunTime.sarray(x,y,z) + inline val CARRAY_SET = 153 // RunTime.carray(x,y,z) + inline val IARRAY_SET = 154 // RunTime.iarray(x,y,z) + inline val LARRAY_SET = 155 // RunTime.larray(x,y,z) + inline val FARRAY_SET = 156 // RunTime.farray(x,y,z) + inline val DARRAY_SET = 157 // RunTime.darray(x,y,z) + inline val OARRAY_SET = 158 // RunTime.oarray(x,y,z) + + inline val B2B = 200 // RunTime.b2b(x) + inline val B2S = 201 // RunTime.b2s(x) + inline val B2C = 202 // RunTime.b2c(x) + inline val B2I = 203 // RunTime.b2i(x) + inline val B2L = 204 // RunTime.b2l(x) + inline val B2F = 205 // RunTime.b2f(x) + inline val B2D = 206 // RunTime.b2d(x) + + inline val S2B = 210 // RunTime.s2b(x) + inline val S2S = 211 // RunTime.s2s(x) + inline val S2C = 212 // RunTime.s2c(x) + inline val S2I = 213 // RunTime.s2i(x) + inline val S2L = 214 // RunTime.s2l(x) + inline val S2F = 215 // RunTime.s2f(x) + inline val S2D = 216 // RunTime.s2d(x) + + inline val C2B = 220 // RunTime.c2b(x) + inline val C2S = 221 // RunTime.c2s(x) + inline val C2C = 222 // RunTime.c2c(x) + inline val C2I = 223 // RunTime.c2i(x) + inline val C2L = 224 // RunTime.c2l(x) + inline val C2F = 225 // RunTime.c2f(x) + inline val C2D = 226 // RunTime.c2d(x) + + inline val I2B = 230 // RunTime.i2b(x) + inline val I2S = 231 // RunTime.i2s(x) + inline val I2C = 232 // RunTime.i2c(x) + inline val I2I = 233 // RunTime.i2i(x) + inline val I2L = 234 // RunTime.i2l(x) + inline val I2F = 235 // RunTime.i2f(x) + inline val I2D = 236 // RunTime.i2d(x) + + inline val L2B = 240 // RunTime.l2b(x) + inline val L2S = 241 // RunTime.l2s(x) + inline val L2C = 242 // RunTime.l2c(x) + inline val L2I = 243 // RunTime.l2i(x) + inline val L2L = 244 // RunTime.l2l(x) + inline val L2F = 245 // RunTime.l2f(x) + inline val L2D = 246 // RunTime.l2d(x) + + inline val F2B = 250 // RunTime.f2b(x) + inline val F2S = 251 // RunTime.f2s(x) + inline val F2C = 252 // RunTime.f2c(x) + inline val F2I = 253 // RunTime.f2i(x) + inline val F2L = 254 // RunTime.f2l(x) + inline val F2F = 255 // RunTime.f2f(x) + inline val F2D = 256 // RunTime.f2d(x) + + inline val D2B = 260 // RunTime.d2b(x) + inline val D2S = 261 // RunTime.d2s(x) + inline val D2C = 262 // RunTime.d2c(x) + inline val D2I = 263 // RunTime.d2i(x) + inline val D2L = 264 // RunTime.d2l(x) + inline val D2F = 265 // RunTime.d2f(x) + inline val D2D = 266 // RunTime.d2d(x) /** Check whether the given operation code is an array operation. */ def isArrayOp(code: Int): Boolean = diff --git a/compiler/src/dotty/tools/backend/jvm/AsmUtils.scala b/compiler/src/dotty/tools/backend/jvm/AsmUtils.scala index 7f5887d99a7f..8a71a09aa7ab 100644 --- a/compiler/src/dotty/tools/backend/jvm/AsmUtils.scala +++ b/compiler/src/dotty/tools/backend/jvm/AsmUtils.scala @@ -19,8 +19,8 @@ object AsmUtils { /** * Print the bytecode of classes generated by GenBCode to the standard output. */ - final val traceClassEnabled = false - final val traceClassPattern = "" + inline val traceClassEnabled = false + inline val traceClassPattern = "" /** * Print the bytedcode of classes as they are serialized by the ASM library. The serialization @@ -28,8 +28,8 @@ object AsmUtils { * introduces stack map frames, it computes the maximal stack sizes, and it replaces dead * code by NOPs (see also https://github.com/scala/scala/pull/3726#issuecomment-42861780). */ - final val traceSerializedClassEnabled = false - final val traceSerializedClassPattern = "" + inline val traceSerializedClassEnabled = false + inline val traceSerializedClassPattern = "" def traceMethod(mnode: MethodNode1): Unit = { println(s"Bytecode for method ${mnode.name}") diff --git a/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala b/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala index 95ebf439fa6d..86150f114d2c 100644 --- a/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala +++ b/compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala @@ -70,7 +70,7 @@ trait BCodeSkelBuilder extends BCodeHelpers { with BCJGenSigGen { // Strangely I can't find this in the asm code 255, but reserving 1 for "this" - final val MaximumJvmParameters = 254 + inline val MaximumJvmParameters = 254 // current class var cnode: ClassNode1 = null diff --git a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala index e30ddd9a55da..56e16647d080 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala @@ -4369,7 +4369,7 @@ class JSCodeGen()(using genCtx: Context) { js.LoadJSConstructor(encodeClassName(sym)) } - private final val GenericGlobalObjectInformationMsg = { + private inline val GenericGlobalObjectInformationMsg = { "\n " + "See https://www.scala-js.org/doc/interoperability/global-scope.html " + "for further information." diff --git a/compiler/src/dotty/tools/backend/sjs/JSPrimitives.scala b/compiler/src/dotty/tools/backend/sjs/JSPrimitives.scala index 372393733051..ac7b492e3e1f 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSPrimitives.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSPrimitives.scala @@ -16,42 +16,42 @@ import scala.collection.mutable object JSPrimitives { - final val FirstJSPrimitiveCode = 300 + inline val FirstJSPrimitiveCode = 300 - final val DYNNEW = FirstJSPrimitiveCode + 1 // Instantiate a new JavaScript object + inline val DYNNEW = FirstJSPrimitiveCode + 1 // Instantiate a new JavaScript object - final val ARR_CREATE = DYNNEW + 1 // js.Array.apply (array literal syntax) + inline val ARR_CREATE = DYNNEW + 1 // js.Array.apply (array literal syntax) - final val TYPEOF = ARR_CREATE + 1 // typeof x - final val JS_NATIVE = TYPEOF + 1 // js.native. Marker method. Fails if tried to be emitted. + inline val TYPEOF = ARR_CREATE + 1 // typeof x + inline val JS_NATIVE = TYPEOF + 1 // js.native. Marker method. Fails if tried to be emitted. - final val UNITVAL = JS_NATIVE + 1 // () value, which is undefined + inline val UNITVAL = JS_NATIVE + 1 // () value, which is undefined - final val JS_IMPORT = UNITVAL + 1 // js.import.apply(specifier) - final val JS_IMPORT_META = JS_IMPORT + 1 // js.import.meta + inline val JS_IMPORT = UNITVAL + 1 // js.import.apply(specifier) + inline val JS_IMPORT_META = JS_IMPORT + 1 // js.import.meta - final val CONSTRUCTOROF = JS_IMPORT_META + 1 // runtime.constructorOf(clazz) - final val CREATE_INNER_JS_CLASS = CONSTRUCTOROF + 1 // runtime.createInnerJSClass - final val CREATE_LOCAL_JS_CLASS = CREATE_INNER_JS_CLASS + 1 // runtime.createLocalJSClass - final val WITH_CONTEXTUAL_JS_CLASS_VALUE = CREATE_LOCAL_JS_CLASS + 1 // runtime.withContextualJSClassValue - final val LINKING_INFO = WITH_CONTEXTUAL_JS_CLASS_VALUE + 1 // runtime.linkingInfo + inline val CONSTRUCTOROF = JS_IMPORT_META + 1 // runtime.constructorOf(clazz) + inline val CREATE_INNER_JS_CLASS = CONSTRUCTOROF + 1 // runtime.createInnerJSClass + inline val CREATE_LOCAL_JS_CLASS = CREATE_INNER_JS_CLASS + 1 // runtime.createLocalJSClass + inline val WITH_CONTEXTUAL_JS_CLASS_VALUE = CREATE_LOCAL_JS_CLASS + 1 // runtime.withContextualJSClassValue + inline val LINKING_INFO = WITH_CONTEXTUAL_JS_CLASS_VALUE + 1 // runtime.linkingInfo - final val STRICT_EQ = LINKING_INFO + 1 // js.special.strictEquals - final val IN = STRICT_EQ + 1 // js.special.in - final val INSTANCEOF = IN + 1 // js.special.instanceof - final val DELETE = INSTANCEOF + 1 // js.special.delete - final val FORIN = DELETE + 1 // js.special.forin - final val DEBUGGER = FORIN + 1 // js.special.debugger + inline val STRICT_EQ = LINKING_INFO + 1 // js.special.strictEquals + inline val IN = STRICT_EQ + 1 // js.special.in + inline val INSTANCEOF = IN + 1 // js.special.instanceof + inline val DELETE = INSTANCEOF + 1 // js.special.delete + inline val FORIN = DELETE + 1 // js.special.forin + inline val DEBUGGER = FORIN + 1 // js.special.debugger - final val THROW = DEBUGGER + 1 + inline val THROW = DEBUGGER + 1 - final val UNION_FROM = THROW + 1 // js.|.from - final val UNION_FROM_TYPE_CONSTRUCTOR = UNION_FROM + 1 // js.|.fromTypeConstructor + inline val UNION_FROM = THROW + 1 // js.|.from + inline val UNION_FROM_TYPE_CONSTRUCTOR = UNION_FROM + 1 // js.|.fromTypeConstructor - final val REFLECT_SELECTABLE_SELECTDYN = UNION_FROM_TYPE_CONSTRUCTOR + 1 // scala.reflect.Selectable.selectDynamic - final val REFLECT_SELECTABLE_APPLYDYN = REFLECT_SELECTABLE_SELECTDYN + 1 // scala.reflect.Selectable.applyDynamic + inline val REFLECT_SELECTABLE_SELECTDYN = UNION_FROM_TYPE_CONSTRUCTOR + 1 // scala.reflect.Selectable.selectDynamic + inline val REFLECT_SELECTABLE_APPLYDYN = REFLECT_SELECTABLE_SELECTDYN + 1 // scala.reflect.Selectable.applyDynamic - final val LastJSPrimitiveCode = REFLECT_SELECTABLE_APPLYDYN + inline val LastJSPrimitiveCode = REFLECT_SELECTABLE_APPLYDYN def isJSPrimitive(code: Int): Boolean = code >= FirstJSPrimitiveCode && code <= LastJSPrimitiveCode diff --git a/compiler/src/dotty/tools/dotc/core/Constants.scala b/compiler/src/dotty/tools/dotc/core/Constants.scala index c3f749a4b607..f2e6f6fc489a 100644 --- a/compiler/src/dotty/tools/dotc/core/Constants.scala +++ b/compiler/src/dotty/tools/dotc/core/Constants.scala @@ -9,19 +9,19 @@ import Decorators._ object Constants { - final val NoTag = 0 - final val UnitTag = 1 - final val BooleanTag = 2 - final val ByteTag = 3 - final val ShortTag = 4 - final val CharTag = 5 - final val IntTag = 6 - final val LongTag = 7 - final val FloatTag = 8 - final val DoubleTag = 9 - final val StringTag = 10 - final val NullTag = 11 - final val ClazzTag = 12 + inline val NoTag = 0 + inline val UnitTag = 1 + inline val BooleanTag = 2 + inline val ByteTag = 3 + inline val ShortTag = 4 + inline val CharTag = 5 + inline val IntTag = 6 + inline val LongTag = 7 + inline val FloatTag = 8 + inline val DoubleTag = 9 + inline val StringTag = 10 + inline val NullTag = 11 + inline val ClazzTag = 12 class Constant(val value: Any, val tag: Int) extends printing.Showable with Product1[Any] { import java.lang.Double.doubleToRawLongBits diff --git a/compiler/src/dotty/tools/dotc/core/Decorators.scala b/compiler/src/dotty/tools/dotc/core/Decorators.scala index 49897a7bb275..3ea05af0292a 100644 --- a/compiler/src/dotty/tools/dotc/core/Decorators.scala +++ b/compiler/src/dotty/tools/dotc/core/Decorators.scala @@ -74,7 +74,7 @@ object Decorators { NoSymbol } - final val MaxFilterRecursions = 10 + inline val MaxFilterRecursions = 10 /** Implements filterConserve, zipWithConserve methods * on lists that avoid duplication of list nodes where feasible. diff --git a/compiler/src/dotty/tools/dotc/core/Hashable.scala b/compiler/src/dotty/tools/dotc/core/Hashable.scala index 1a1550183f93..713555bed517 100644 --- a/compiler/src/dotty/tools/dotc/core/Hashable.scala +++ b/compiler/src/dotty/tools/dotc/core/Hashable.scala @@ -19,20 +19,20 @@ object Hashable { /** A hash value indicating that the underlying type is not * cached in uniques. */ - final val NotCached = 0 + inline val NotCached = 0 /** An alternative value returned from `hash` if the * computed hashCode would be `NotCached`. */ - private[core] final val NotCachedAlt = Int.MinValue + private[core] inline val NotCachedAlt = Int.MinValue /** A value that indicates that the hash code is unknown */ - private[core] final val HashUnknown = 1234 + private[core] inline val HashUnknown = 1234 /** An alternative value if computeHash would otherwise yield HashUnknown */ - private[core] final val HashUnknownAlt = 4321 + private[core] inline val HashUnknownAlt = 4321 } trait Hashable { diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index d0b7e811eb4b..fb35ac0ac91f 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -17,7 +17,7 @@ object NameOps { object compactify { lazy val md5: MessageDigest = MessageDigest.getInstance("MD5") - final val CLASSFILE_NAME_CHAR_LIMIT = 240 + inline val CLASSFILE_NAME_CHAR_LIMIT = 240 /** COMPACTIFY * diff --git a/compiler/src/dotty/tools/dotc/core/NameTags.scala b/compiler/src/dotty/tools/dotc/core/NameTags.scala index 67dfcec73c53..7ee7758a506b 100644 --- a/compiler/src/dotty/tools/dotc/core/NameTags.scala +++ b/compiler/src/dotty/tools/dotc/core/NameTags.scala @@ -5,32 +5,32 @@ import dotty.tools.tasty.TastyFormat /** The possible tags of a NameKind */ object NameTags extends TastyFormat.NameTags { - final val FLATTENED = 5 // A flat name, generated by Flatten + inline val FLATTENED = 5 // A flat name, generated by Flatten - final val TRAITSETTER = 6 // A Scala-2 trait setter, generated by AugmentScala2Traits + inline val TRAITSETTER = 6 // A Scala-2 trait setter, generated by AugmentScala2Traits - final val OUTERSELECT = 13 // A name `_outer`, used by the inliner to indicate an + inline val OUTERSELECT = 13 // A name `_outer`, used by the inliner to indicate an // outer accessor that will be filled in by ExplicitOuter. // indicates the number of hops needed to select the outer field. - final val PROTECTEDACCESSOR = 24 // The name of a protected accesor `protected$` created by ProtectedAccessors. + inline val PROTECTEDACCESSOR = 24 // The name of a protected accesor `protected$` created by ProtectedAccessors. - final val INITIALIZER = 26 // A mixin initializer method + inline val INITIALIZER = 26 // A mixin initializer method - final val FIELD = 29 // Used by Memoize to tag the name of a class member field. + inline val FIELD = 29 // Used by Memoize to tag the name of a class member field. - final val EXTMETH = 30 // Used by ExtensionMethods for the name of an extension method + inline val EXTMETH = 30 // Used by ExtensionMethods for the name of an extension method // implementing a value class method. - final val ADAPTEDCLOSURE = 31 // Used in Erasure to adapt closures over primitive types. + inline val ADAPTEDCLOSURE = 31 // Used in Erasure to adapt closures over primitive types. - final val DIRECT = 32 // Used to define implementations of methods with + inline val DIRECT = 32 // Used to define implementations of methods with // erased context function results that can override some // other method. - final val PARAMACC = 33 // Used for a private parameter alias + inline val PARAMACC = 33 // Used for a private parameter alias - final val SETTER = 34 // A synthesized += suffix. + inline val SETTER = 34 // A synthesized += suffix. def nameTagToString(tag: Int): String = tag match { case UTF8 => "UTF8" diff --git a/compiler/src/dotty/tools/dotc/core/Periods.scala b/compiler/src/dotty/tools/dotc/core/Periods.scala index d5944beedc2a..44d83dcb5278 100644 --- a/compiler/src/dotty/tools/dotc/core/Periods.scala +++ b/compiler/src/dotty/tools/dotc/core/Periods.scala @@ -126,18 +126,18 @@ object Periods { /** An ordinal number for compiler runs. First run has number 1. */ type RunId = Int - final val NoRunId = 0 - final val InitialRunId = 1 - final val RunWidth = java.lang.Integer.SIZE - PhaseWidth * 2 - 1/* sign */ - final val MaxPossibleRunId = (1 << RunWidth) - 1 + inline val NoRunId = 0 + inline val InitialRunId = 1 + inline val RunWidth = java.lang.Integer.SIZE - PhaseWidth * 2 - 1/* sign */ + inline val MaxPossibleRunId = (1 << RunWidth) - 1 /** An ordinal number for phases. First phase has number 1. */ type PhaseId = Int - final val NoPhaseId = 0 - final val FirstPhaseId = 1 + inline val NoPhaseId = 0 + inline val FirstPhaseId = 1 /** The number of bits needed to encode a phase identifier. */ - final val PhaseWidth = 7 - final val PhaseMask = (1 << PhaseWidth) - 1 - final val MaxPossiblePhaseId = PhaseMask + inline val PhaseWidth = 7 + inline val PhaseMask = (1 << PhaseWidth) - 1 + inline val MaxPossiblePhaseId = PhaseMask } diff --git a/compiler/src/dotty/tools/dotc/core/Scopes.scala b/compiler/src/dotty/tools/dotc/core/Scopes.scala index 5dc7ce168c24..1553093a2b87 100644 --- a/compiler/src/dotty/tools/dotc/core/Scopes.scala +++ b/compiler/src/dotty/tools/dotc/core/Scopes.scala @@ -24,19 +24,19 @@ import collection.mutable object Scopes { /** Maximal fill factor of hash table */ - private final val FillFactor = 2.0/3.0 + private inline val FillFactor = 2.0/3.0 /** A hashtable is created once current size exceeds MinHash * FillFactor * The initial hash table has twice that size (i.e 16). * This value must be a power of two, so that the index of an element can * be computed as element.hashCode & (hashTable.length - 1) */ - final val MinHashedScopeSize = 8 + inline val MinHashedScopeSize = 8 /** The maximal permissible number of recursions when creating * a hashtable */ - private final val MaxRecursions = 1000 + private inline val MaxRecursions = 1000 /** A function that optionally produces synthesized symbols with * the given name in the given context. Returns `NoSymbol` if the diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 2e0b229ca42c..349f80d11d8a 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -13,33 +13,33 @@ object StdNames { /** Base strings from which synthetic names are derived. */ object str { - final val SETTER_SUFFIX = "_=" - final val EXPAND_SEPARATOR = "$$" - final val TRAIT_SETTER_SEPARATOR = "$_setter_$" - final val SUPER_PREFIX = "super$" - final val INITIALIZER_PREFIX = "initial$" - final val AVOID_CLASH_SUFFIX = "$_avoid_name_clash_$" - final val MODULE_SUFFIX = "$" - final val TOPLEVEL_SUFFIX = "$package" - final val NAME_JOIN = "$" - final val DEFAULT_GETTER = "$default$" - final val LOCALDUMMY_PREFIX = "]""", """\$""") } diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileConstants.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileConstants.scala index 93603e8a9d37..3b05ee351b86 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileConstants.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileConstants.scala @@ -6,11 +6,11 @@ import scala.annotation.switch object ClassfileConstants { - final val JAVA_MAGIC = 0xCAFEBABE - final val JAVA_MAJOR_VERSION = 45 - final val JAVA_MINOR_VERSION = 3 + inline val JAVA_MAGIC = 0xCAFEBABE + inline val JAVA_MAJOR_VERSION = 45 + inline val JAVA_MINOR_VERSION = 3 - final val JAVA8_MAJOR_VERSION = 52 + inline val JAVA8_MAJOR_VERSION = 52 /** (see http://java.sun.com/docs/books/jvms/second_edition/jvms-clarify.html) * @@ -38,298 +38,298 @@ object ClassfileConstants { * https://groups.google.com/forum/?hl=en#!topic/jvm-languages/jVhzvq8-ZIk * */ // Class Field Method - final val JAVA_ACC_PUBLIC = 0x0001 // X X X - final val JAVA_ACC_PRIVATE = 0x0002 // X X - final val JAVA_ACC_PROTECTED = 0x0004 // X X - final val JAVA_ACC_STATIC = 0x0008 // X X - final val JAVA_ACC_FINAL = 0x0010 // X X X - final val JAVA_ACC_SUPER = 0x0020 // X - final val JAVA_ACC_SYNCHRONIZED = 0x0020 // X - final val JAVA_ACC_VOLATILE = 0x0040 // X - final val JAVA_ACC_BRIDGE = 0x0040 // X - final val JAVA_ACC_TRANSIENT = 0x0080 // X - final val JAVA_ACC_VARARGS = 0x0080 // X - final val JAVA_ACC_NATIVE = 0x0100 // X - final val JAVA_ACC_INTERFACE = 0x0200 // X - final val JAVA_ACC_ABSTRACT = 0x0400 // X X - final val JAVA_ACC_STRICT = 0x0800 // X - final val JAVA_ACC_SYNTHETIC = 0x1000 // X X X - final val JAVA_ACC_ANNOTATION = 0x2000 // X - final val JAVA_ACC_ENUM = 0x4000 // X X + inline val JAVA_ACC_PUBLIC = 0x0001 // X X X + inline val JAVA_ACC_PRIVATE = 0x0002 // X X + inline val JAVA_ACC_PROTECTED = 0x0004 // X X + inline val JAVA_ACC_STATIC = 0x0008 // X X + inline val JAVA_ACC_FINAL = 0x0010 // X X X + inline val JAVA_ACC_SUPER = 0x0020 // X + inline val JAVA_ACC_SYNCHRONIZED = 0x0020 // X + inline val JAVA_ACC_VOLATILE = 0x0040 // X + inline val JAVA_ACC_BRIDGE = 0x0040 // X + inline val JAVA_ACC_TRANSIENT = 0x0080 // X + inline val JAVA_ACC_VARARGS = 0x0080 // X + inline val JAVA_ACC_NATIVE = 0x0100 // X + inline val JAVA_ACC_INTERFACE = 0x0200 // X + inline val JAVA_ACC_ABSTRACT = 0x0400 // X X + inline val JAVA_ACC_STRICT = 0x0800 // X + inline val JAVA_ACC_SYNTHETIC = 0x1000 // X X X + inline val JAVA_ACC_ANNOTATION = 0x2000 // X + inline val JAVA_ACC_ENUM = 0x4000 // X X // tags describing the type of a literal in the constant pool - final val CONSTANT_UTF8 = 1 - final val CONSTANT_UNICODE = 2 - final val CONSTANT_INTEGER = 3 - final val CONSTANT_FLOAT = 4 - final val CONSTANT_LONG = 5 - final val CONSTANT_DOUBLE = 6 - final val CONSTANT_CLASS = 7 - final val CONSTANT_STRING = 8 - final val CONSTANT_FIELDREF = 9 - final val CONSTANT_METHODREF = 10 - final val CONSTANT_INTFMETHODREF = 11 - final val CONSTANT_NAMEANDTYPE = 12 - - final val CONSTANT_METHODHANDLE = 15 - final val CONSTANT_METHODTYPE = 16 - final val CONSTANT_INVOKEDYNAMIC = 18 + inline val CONSTANT_UTF8 = 1 + inline val CONSTANT_UNICODE = 2 + inline val CONSTANT_INTEGER = 3 + inline val CONSTANT_FLOAT = 4 + inline val CONSTANT_LONG = 5 + inline val CONSTANT_DOUBLE = 6 + inline val CONSTANT_CLASS = 7 + inline val CONSTANT_STRING = 8 + inline val CONSTANT_FIELDREF = 9 + inline val CONSTANT_METHODREF = 10 + inline val CONSTANT_INTFMETHODREF = 11 + inline val CONSTANT_NAMEANDTYPE = 12 + + inline val CONSTANT_METHODHANDLE = 15 + inline val CONSTANT_METHODTYPE = 16 + inline val CONSTANT_INVOKEDYNAMIC = 18 // tags describing the type of a literal in attribute values - final val BYTE_TAG = 'B' - final val CHAR_TAG = 'C' - final val DOUBLE_TAG = 'D' - final val FLOAT_TAG = 'F' - final val INT_TAG = 'I' - final val LONG_TAG = 'J' - final val SHORT_TAG = 'S' - final val BOOL_TAG = 'Z' - final val STRING_TAG = 's' - final val ENUM_TAG = 'e' - final val CLASS_TAG = 'c' - final val ARRAY_TAG = '[' - final val VOID_TAG = 'V' - final val TVAR_TAG = 'T' - final val OBJECT_TAG = 'L' - final val ANNOTATION_TAG = '@' - final val SCALA_NOTHING = "scala.runtime.Nothing$" - final val SCALA_NULL = "scala.runtime.Null$" + inline val BYTE_TAG = 'B' + inline val CHAR_TAG = 'C' + inline val DOUBLE_TAG = 'D' + inline val FLOAT_TAG = 'F' + inline val INT_TAG = 'I' + inline val LONG_TAG = 'J' + inline val SHORT_TAG = 'S' + inline val BOOL_TAG = 'Z' + inline val STRING_TAG = 's' + inline val ENUM_TAG = 'e' + inline val CLASS_TAG = 'c' + inline val ARRAY_TAG = '[' + inline val VOID_TAG = 'V' + inline val TVAR_TAG = 'T' + inline val OBJECT_TAG = 'L' + inline val ANNOTATION_TAG = '@' + inline val SCALA_NOTHING = "scala.runtime.Nothing$" + inline val SCALA_NULL = "scala.runtime.Null$" // tags describing the type of newarray - final val T_BOOLEAN = 4 - final val T_CHAR = 5 - final val T_FLOAT = 6 - final val T_DOUBLE = 7 - final val T_BYTE = 8 - final val T_SHORT = 9 - final val T_INT = 10 - final val T_LONG = 11 + inline val T_BOOLEAN = 4 + inline val T_CHAR = 5 + inline val T_FLOAT = 6 + inline val T_DOUBLE = 7 + inline val T_BYTE = 8 + inline val T_SHORT = 9 + inline val T_INT = 10 + inline val T_LONG = 11 // JVM mnemonics - final val nop = 0x00 - final val aconst_null = 0x01 - final val iconst_m1 = 0x02 - - final val iconst_0 = 0x03 - final val iconst_1 = 0x04 - final val iconst_2 = 0x05 - final val iconst_3 = 0x06 - final val iconst_4 = 0x07 - final val iconst_5 = 0x08 - - final val lconst_0 = 0x09 - final val lconst_1 = 0x0a - final val fconst_0 = 0x0b - final val fconst_1 = 0x0c - final val fconst_2 = 0x0d - final val dconst_0 = 0x0e - final val dconst_1 = 0x0f - - final val bipush = 0x10 - final val sipush = 0x11 - final val ldc = 0x12 - final val ldc_w = 0x13 - final val ldc2_w = 0x14 - - final val iload = 0x15 - final val lload = 0x16 - final val fload = 0x17 - final val dload = 0x18 - final val aload = 0x19 - - final val iload_0 = 0x1a - final val iload_1 = 0x1b - final val iload_2 = 0x1c - final val iload_3 = 0x1d - final val lload_0 = 0x1e - final val lload_1 = 0x1f - final val lload_2 = 0x20 - final val lload_3 = 0x21 - final val fload_0 = 0x22 - final val fload_1 = 0x23 - final val fload_2 = 0x24 - final val fload_3 = 0x25 - final val dload_0 = 0x26 - final val dload_1 = 0x27 - final val dload_2 = 0x28 - final val dload_3 = 0x29 - final val aload_0 = 0x2a - final val aload_1 = 0x2b - final val aload_2 = 0x2c - final val aload_3 = 0x2d - final val iaload = 0x2e - final val laload = 0x2f - final val faload = 0x30 - final val daload = 0x31 - final val aaload = 0x32 - final val baload = 0x33 - final val caload = 0x34 - final val saload = 0x35 - - final val istore = 0x36 - final val lstore = 0x37 - final val fstore = 0x38 - final val dstore = 0x39 - final val astore = 0x3a - final val istore_0 = 0x3b - final val istore_1 = 0x3c - final val istore_2 = 0x3d - final val istore_3 = 0x3e - final val lstore_0 = 0x3f - final val lstore_1 = 0x40 - final val lstore_2 = 0x41 - final val lstore_3 = 0x42 - final val fstore_0 = 0x43 - final val fstore_1 = 0x44 - final val fstore_2 = 0x45 - final val fstore_3 = 0x46 - final val dstore_0 = 0x47 - final val dstore_1 = 0x48 - final val dstore_2 = 0x49 - final val dstore_3 = 0x4a - final val astore_0 = 0x4b - final val astore_1 = 0x4c - final val astore_2 = 0x4d - final val astore_3 = 0x4e - final val iastore = 0x4f - final val lastore = 0x50 - final val fastore = 0x51 - final val dastore = 0x52 - final val aastore = 0x53 - final val bastore = 0x54 - final val castore = 0x55 - final val sastore = 0x56 - - final val pop = 0x57 - final val pop2 = 0x58 - final val dup = 0x59 - final val dup_x1 = 0x5a - final val dup_x2 = 0x5b - final val dup2 = 0x5c - final val dup2_x1 = 0x5d - final val dup2_x2 = 0x5e - final val swap = 0x5f - - final val iadd = 0x60 - final val ladd = 0x61 - final val fadd = 0x62 - final val dadd = 0x63 - final val isub = 0x64 - final val lsub = 0x65 - final val fsub = 0x66 - final val dsub = 0x67 - final val imul = 0x68 - final val lmul = 0x69 - final val fmul = 0x6a - final val dmul = 0x6b - final val idiv = 0x6c - final val ldiv = 0x6d - final val fdiv = 0x6e - final val ddiv = 0x6f - final val irem = 0x70 - final val lrem = 0x71 - final val frem = 0x72 - final val drem = 0x73 - - final val ineg = 0x74 - final val lneg = 0x75 - final val fneg = 0x76 - final val dneg = 0x77 - - final val ishl = 0x78 - final val lshl = 0x79 - final val ishr = 0x7a - final val lshr = 0x7b - final val iushr = 0x7c - final val lushr = 0x7d - final val iand = 0x7e - final val land = 0x7f - final val ior = 0x80 - final val lor = 0x81 - final val ixor = 0x82 - final val lxor = 0x83 - final val iinc = 0x84 - - final val i2l = 0x85 - final val i2f = 0x86 - final val i2d = 0x87 - final val l2i = 0x88 - final val l2f = 0x89 - final val l2d = 0x8a - final val f2i = 0x8b - final val f2l = 0x8c - final val f2d = 0x8d - final val d2i = 0x8e - final val d2l = 0x8f - final val d2f = 0x90 - final val i2b = 0x91 - final val i2c = 0x92 - final val i2s = 0x93 - - final val lcmp = 0x94 - final val fcmpl = 0x95 - final val fcmpg = 0x96 - final val dcmpl = 0x97 - final val dcmpg = 0x98 - - final val ifeq = 0x99 - final val ifne = 0x9a - final val iflt = 0x9b - final val ifge = 0x9c - final val ifgt = 0x9d - final val ifle = 0x9e - final val if_icmpeq = 0x9f - final val if_icmpne = 0xa0 - final val if_icmplt = 0xa1 - final val if_icmpge = 0xa2 - final val if_icmpgt = 0xa3 - final val if_icmple = 0xa4 - final val if_acmpeq = 0xa5 - final val if_acmpne = 0xa6 - final val goto = 0xa7 - final val jsr = 0xa8 - final val ret = 0xa9 - final val tableswitch = 0xaa - final val lookupswitch = 0xab - final val ireturn = 0xac - final val lreturn = 0xad - final val freturn = 0xae - final val dreturn = 0xaf - final val areturn = 0xb0 - final val return_ = 0xb1 - - final val getstatic = 0xb2 - final val putstatic = 0xb3 - final val getfield = 0xb4 - final val putfield = 0xb5 - - final val invokevirtual = 0xb6 - final val invokespecial = 0xb7 - final val invokestatic = 0xb8 - final val invokeinterface = 0xb9 - final val xxxunusedxxxx = 0xba - - final val new_ = 0xbb - final val newarray = 0xbc - final val anewarray = 0xbd - final val arraylength = 0xbe - final val athrow = 0xbf - final val checkcast = 0xc0 - final val instanceof = 0xc1 - final val monitorenter = 0xc2 - final val monitorexit = 0xc3 - final val wide = 0xc4 - final val multianewarray = 0xc5 - final val ifnull = 0xc6 - final val ifnonnull = 0xc7 - final val goto_w = 0xc8 - final val jsr_w = 0xc9 + inline val nop = 0x00 + inline val aconst_null = 0x01 + inline val iconst_m1 = 0x02 + + inline val iconst_0 = 0x03 + inline val iconst_1 = 0x04 + inline val iconst_2 = 0x05 + inline val iconst_3 = 0x06 + inline val iconst_4 = 0x07 + inline val iconst_5 = 0x08 + + inline val lconst_0 = 0x09 + inline val lconst_1 = 0x0a + inline val fconst_0 = 0x0b + inline val fconst_1 = 0x0c + inline val fconst_2 = 0x0d + inline val dconst_0 = 0x0e + inline val dconst_1 = 0x0f + + inline val bipush = 0x10 + inline val sipush = 0x11 + inline val ldc = 0x12 + inline val ldc_w = 0x13 + inline val ldc2_w = 0x14 + + inline val iload = 0x15 + inline val lload = 0x16 + inline val fload = 0x17 + inline val dload = 0x18 + inline val aload = 0x19 + + inline val iload_0 = 0x1a + inline val iload_1 = 0x1b + inline val iload_2 = 0x1c + inline val iload_3 = 0x1d + inline val lload_0 = 0x1e + inline val lload_1 = 0x1f + inline val lload_2 = 0x20 + inline val lload_3 = 0x21 + inline val fload_0 = 0x22 + inline val fload_1 = 0x23 + inline val fload_2 = 0x24 + inline val fload_3 = 0x25 + inline val dload_0 = 0x26 + inline val dload_1 = 0x27 + inline val dload_2 = 0x28 + inline val dload_3 = 0x29 + inline val aload_0 = 0x2a + inline val aload_1 = 0x2b + inline val aload_2 = 0x2c + inline val aload_3 = 0x2d + inline val iaload = 0x2e + inline val laload = 0x2f + inline val faload = 0x30 + inline val daload = 0x31 + inline val aaload = 0x32 + inline val baload = 0x33 + inline val caload = 0x34 + inline val saload = 0x35 + + inline val istore = 0x36 + inline val lstore = 0x37 + inline val fstore = 0x38 + inline val dstore = 0x39 + inline val astore = 0x3a + inline val istore_0 = 0x3b + inline val istore_1 = 0x3c + inline val istore_2 = 0x3d + inline val istore_3 = 0x3e + inline val lstore_0 = 0x3f + inline val lstore_1 = 0x40 + inline val lstore_2 = 0x41 + inline val lstore_3 = 0x42 + inline val fstore_0 = 0x43 + inline val fstore_1 = 0x44 + inline val fstore_2 = 0x45 + inline val fstore_3 = 0x46 + inline val dstore_0 = 0x47 + inline val dstore_1 = 0x48 + inline val dstore_2 = 0x49 + inline val dstore_3 = 0x4a + inline val astore_0 = 0x4b + inline val astore_1 = 0x4c + inline val astore_2 = 0x4d + inline val astore_3 = 0x4e + inline val iastore = 0x4f + inline val lastore = 0x50 + inline val fastore = 0x51 + inline val dastore = 0x52 + inline val aastore = 0x53 + inline val bastore = 0x54 + inline val castore = 0x55 + inline val sastore = 0x56 + + inline val pop = 0x57 + inline val pop2 = 0x58 + inline val dup = 0x59 + inline val dup_x1 = 0x5a + inline val dup_x2 = 0x5b + inline val dup2 = 0x5c + inline val dup2_x1 = 0x5d + inline val dup2_x2 = 0x5e + inline val swap = 0x5f + + inline val iadd = 0x60 + inline val ladd = 0x61 + inline val fadd = 0x62 + inline val dadd = 0x63 + inline val isub = 0x64 + inline val lsub = 0x65 + inline val fsub = 0x66 + inline val dsub = 0x67 + inline val imul = 0x68 + inline val lmul = 0x69 + inline val fmul = 0x6a + inline val dmul = 0x6b + inline val idiv = 0x6c + inline val ldiv = 0x6d + inline val fdiv = 0x6e + inline val ddiv = 0x6f + inline val irem = 0x70 + inline val lrem = 0x71 + inline val frem = 0x72 + inline val drem = 0x73 + + inline val ineg = 0x74 + inline val lneg = 0x75 + inline val fneg = 0x76 + inline val dneg = 0x77 + + inline val ishl = 0x78 + inline val lshl = 0x79 + inline val ishr = 0x7a + inline val lshr = 0x7b + inline val iushr = 0x7c + inline val lushr = 0x7d + inline val iand = 0x7e + inline val land = 0x7f + inline val ior = 0x80 + inline val lor = 0x81 + inline val ixor = 0x82 + inline val lxor = 0x83 + inline val iinc = 0x84 + + inline val i2l = 0x85 + inline val i2f = 0x86 + inline val i2d = 0x87 + inline val l2i = 0x88 + inline val l2f = 0x89 + inline val l2d = 0x8a + inline val f2i = 0x8b + inline val f2l = 0x8c + inline val f2d = 0x8d + inline val d2i = 0x8e + inline val d2l = 0x8f + inline val d2f = 0x90 + inline val i2b = 0x91 + inline val i2c = 0x92 + inline val i2s = 0x93 + + inline val lcmp = 0x94 + inline val fcmpl = 0x95 + inline val fcmpg = 0x96 + inline val dcmpl = 0x97 + inline val dcmpg = 0x98 + + inline val ifeq = 0x99 + inline val ifne = 0x9a + inline val iflt = 0x9b + inline val ifge = 0x9c + inline val ifgt = 0x9d + inline val ifle = 0x9e + inline val if_icmpeq = 0x9f + inline val if_icmpne = 0xa0 + inline val if_icmplt = 0xa1 + inline val if_icmpge = 0xa2 + inline val if_icmpgt = 0xa3 + inline val if_icmple = 0xa4 + inline val if_acmpeq = 0xa5 + inline val if_acmpne = 0xa6 + inline val goto = 0xa7 + inline val jsr = 0xa8 + inline val ret = 0xa9 + inline val tableswitch = 0xaa + inline val lookupswitch = 0xab + inline val ireturn = 0xac + inline val lreturn = 0xad + inline val freturn = 0xae + inline val dreturn = 0xaf + inline val areturn = 0xb0 + inline val return_ = 0xb1 + + inline val getstatic = 0xb2 + inline val putstatic = 0xb3 + inline val getfield = 0xb4 + inline val putfield = 0xb5 + + inline val invokevirtual = 0xb6 + inline val invokespecial = 0xb7 + inline val invokestatic = 0xb8 + inline val invokeinterface = 0xb9 + inline val xxxunusedxxxx = 0xba + + inline val new_ = 0xbb + inline val newarray = 0xbc + inline val anewarray = 0xbd + inline val arraylength = 0xbe + inline val athrow = 0xbf + inline val checkcast = 0xc0 + inline val instanceof = 0xc1 + inline val monitorenter = 0xc2 + inline val monitorexit = 0xc3 + inline val wide = 0xc4 + inline val multianewarray = 0xc5 + inline val ifnull = 0xc6 + inline val ifnonnull = 0xc7 + inline val goto_w = 0xc8 + inline val jsr_w = 0xc9 // reserved opcodes - final val breakpoint = 0xca - final val impdep1 = 0xfe - final val impdep2 = 0xff + inline val breakpoint = 0xca + inline val impdep1 = 0xfe + inline val impdep2 = 0xff import Flags._ abstract class FlagTranslation { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala index 268b02b4389f..a3dedaaec685 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala @@ -13,7 +13,7 @@ import ast.untpd.Tree class TreeBuffer extends TastyBuffer(50000) { - private final val ItemsOverOffsets = 2 + private inline val ItemsOverOffsets = 2 private val initialOffsetSize = bytes.length / (AddrWidth * ItemsOverOffsets) private var offsets = new Array[Int](initialOffsetSize) private var isRelative = new Array[Boolean](initialOffsetSize) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index e4a5c0ae8c6d..af186e825591 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -1522,9 +1522,9 @@ object TreeUnpickler { /** An enumeration indicating which subtrees should be added to an OwnerTree. */ type MemberDefMode = Int - final val MemberDefsOnly = 0 // add only member defs; skip other statements - final val NoMemberDefs = 1 // add only statements that are not member defs - final val AllDefs = 2 // add everything + inline val MemberDefsOnly = 0 // add only member defs; skip other statements + inline val NoMemberDefs = 1 // add only statements that are not member defs + inline val AllDefs = 2 // add everything class TreeWithoutOwner extends Exception } diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala index fc06ce4da8a3..2aeb1bdeefcc 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala @@ -189,9 +189,9 @@ class PickleBuffer(data: Array[Byte], from: Int, to: Int) { object PickleBuffer { - private final val ScalaFlagEnd = 48 - private final val ChunkBits = 8 - private final val ChunkSize = 1 << ChunkBits + private inline val ScalaFlagEnd = 48 + private inline val ChunkBits = 8 + private inline val ChunkSize = 1 << ChunkBits private type FlagMap = Array[Array[Long]] private val (scalaTermFlagMap, scalaTypeFlagMap) = { diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleFormat.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleFormat.scala index a9a64a9bb7ee..f135de7e43e9 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleFormat.scala @@ -119,109 +119,109 @@ object PickleFormat { val MajorVersion: Int = 5 val MinorVersion: Int = 2 - final val TERMname = 1 - final val TYPEname = 2 - final val NONEsym = 3 - final val TYPEsym = 4 - final val ALIASsym = 5 - final val CLASSsym = 6 - final val MODULEsym = 7 - final val VALsym = 8 - final val EXTref = 9 - final val EXTMODCLASSref = 10 - final val NOtpe = 11 - final val NOPREFIXtpe = 12 - final val THIStpe = 13 - final val SINGLEtpe = 14 - final val CONSTANTtpe = 15 - final val TYPEREFtpe = 16 - final val TYPEBOUNDStpe = 17 - final val REFINEDtpe = 18 - final val CLASSINFOtpe = 19 - final val METHODtpe = 20 - final val POLYtpe = 21 - final val IMPLICITMETHODtpe = 22 // no longer generated + inline val TERMname = 1 + inline val TYPEname = 2 + inline val NONEsym = 3 + inline val TYPEsym = 4 + inline val ALIASsym = 5 + inline val CLASSsym = 6 + inline val MODULEsym = 7 + inline val VALsym = 8 + inline val EXTref = 9 + inline val EXTMODCLASSref = 10 + inline val NOtpe = 11 + inline val NOPREFIXtpe = 12 + inline val THIStpe = 13 + inline val SINGLEtpe = 14 + inline val CONSTANTtpe = 15 + inline val TYPEREFtpe = 16 + inline val TYPEBOUNDStpe = 17 + inline val REFINEDtpe = 18 + inline val CLASSINFOtpe = 19 + inline val METHODtpe = 20 + inline val POLYtpe = 21 + inline val IMPLICITMETHODtpe = 22 // no longer generated - final val LITERAL = 23 // base line for literals - final val LITERALunit = 24 - final val LITERALboolean = 25 - final val LITERALbyte = 26 - final val LITERALshort = 27 - final val LITERALchar = 28 - final val LITERALint = 29 - final val LITERALlong = 30 - final val LITERALfloat = 31 - final val LITERALdouble = 32 - final val LITERALstring = 33 - final val LITERALnull = 34 - final val LITERALclass = 35 - final val LITERALenum = 36 - final val SYMANNOT = 40 - final val CHILDREN = 41 - final val ANNOTATEDtpe = 42 - final val ANNOTINFO = 43 - final val ANNOTARGARRAY = 44 + inline val LITERAL = 23 // base line for literals + inline val LITERALunit = 24 + inline val LITERALboolean = 25 + inline val LITERALbyte = 26 + inline val LITERALshort = 27 + inline val LITERALchar = 28 + inline val LITERALint = 29 + inline val LITERALlong = 30 + inline val LITERALfloat = 31 + inline val LITERALdouble = 32 + inline val LITERALstring = 33 + inline val LITERALnull = 34 + inline val LITERALclass = 35 + inline val LITERALenum = 36 + inline val SYMANNOT = 40 + inline val CHILDREN = 41 + inline val ANNOTATEDtpe = 42 + inline val ANNOTINFO = 43 + inline val ANNOTARGARRAY = 44 - final val SUPERtpe = 46 - final val DEBRUIJNINDEXtpe = 47 // no longer generated - final val EXISTENTIALtpe = 48 + inline val SUPERtpe = 46 + inline val DEBRUIJNINDEXtpe = 47 // no longer generated + inline val EXISTENTIALtpe = 48 - final val TREE = 49 // prefix code that means a tree is coming - final val EMPTYtree = 1 - final val PACKAGEtree = 2 - final val CLASStree = 3 - final val MODULEtree = 4 - final val VALDEFtree = 5 - final val DEFDEFtree = 6 - final val TYPEDEFtree = 7 - final val LABELtree = 8 - final val IMPORTtree = 9 - final val DOCDEFtree = 11 - final val TEMPLATEtree = 12 - final val BLOCKtree = 13 - final val CASEtree = 14 + inline val TREE = 49 // prefix code that means a tree is coming + inline val EMPTYtree = 1 + inline val PACKAGEtree = 2 + inline val CLASStree = 3 + inline val MODULEtree = 4 + inline val VALDEFtree = 5 + inline val DEFDEFtree = 6 + inline val TYPEDEFtree = 7 + inline val LABELtree = 8 + inline val IMPORTtree = 9 + inline val DOCDEFtree = 11 + inline val TEMPLATEtree = 12 + inline val BLOCKtree = 13 + inline val CASEtree = 14 // This node type has been removed. - // final val SEQUENCEtree = 15 - final val ALTERNATIVEtree = 16 - final val STARtree = 17 - final val BINDtree = 18 - final val UNAPPLYtree = 19 - final val ARRAYVALUEtree = 20 - final val FUNCTIONtree = 21 - final val ASSIGNtree = 22 - final val IFtree = 23 - final val MATCHtree = 24 - final val RETURNtree = 25 - final val TREtree = 26 - final val THROWtree = 27 - final val NEWtree = 28 - final val TYPEDtree = 29 - final val TYPEAPPLYtree = 30 - final val APPLYtree = 31 - final val APPLYDYNAMICtree = 32 - final val SUPERtree = 33 - final val THIStree = 34 - final val SELECTtree = 35 - final val IDENTtree = 36 - final val LITERALtree = 37 - final val TYPEtree = 38 - final val ANNOTATEDtree = 39 - final val SINGLETONTYPEtree = 40 - final val SELECTFROMTYPEtree = 41 - final val COMPOUNDTYPEtree = 42 - final val APPLIEDTYPEtree = 43 - final val TYPEBOUNDStree = 44 - final val EXISTENTIALTYPEtree = 45 + // inline val SEQUENCEtree = 15 + inline val ALTERNATIVEtree = 16 + inline val STARtree = 17 + inline val BINDtree = 18 + inline val UNAPPLYtree = 19 + inline val ARRAYVALUEtree = 20 + inline val FUNCTIONtree = 21 + inline val ASSIGNtree = 22 + inline val IFtree = 23 + inline val MATCHtree = 24 + inline val RETURNtree = 25 + inline val TREtree = 26 + inline val THROWtree = 27 + inline val NEWtree = 28 + inline val TYPEDtree = 29 + inline val TYPEAPPLYtree = 30 + inline val APPLYtree = 31 + inline val APPLYDYNAMICtree = 32 + inline val SUPERtree = 33 + inline val THIStree = 34 + inline val SELECTtree = 35 + inline val IDENTtree = 36 + inline val LITERALtree = 37 + inline val TYPEtree = 38 + inline val ANNOTATEDtree = 39 + inline val SINGLETONTYPEtree = 40 + inline val SELECTFROMTYPEtree = 41 + inline val COMPOUNDTYPEtree = 42 + inline val APPLIEDTYPEtree = 43 + inline val TYPEBOUNDStree = 44 + inline val EXISTENTIALTYPEtree = 45 - final val MODIFIERS = 50 + inline val MODIFIERS = 50 - final val firstSymTag = NONEsym - final val lastSymTag = VALsym - final val lastExtSymTag = EXTMODCLASSref + inline val firstSymTag = NONEsym + inline val lastSymTag = VALsym + inline val lastExtSymTag = EXTMODCLASSref } //The following two are no longer accurate, because ANNOTATEDtpe, //SUPERtpe, ... are not in the same range as the other types - //final val firstTypeTag = NOtpe - //final val lastTypeTag = POLYtpe + //inline val firstTypeTag = NOtpe + //inline val lastTypeTag = POLYtpe diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Flags.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Flags.scala index 5749706270c9..6cf08b3384d9 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Flags.scala @@ -12,96 +12,96 @@ package unpickleScala2 /** Scala2 flags, adapted from https://github.com/scala/scala/blob/2.11.x/src/reflect/scala/reflect/internal/Flags.scala */ object Scala2Flags { - final val IMPLICIT = 1 << 9 - final val FINAL = 1 << 5 // May not be overridden. Note that java final implies much more than scala final. - final val PRIVATE = 1 << 2 - final val PROTECTED = 1 << 0 + inline val IMPLICIT = 1 << 9 + inline val FINAL = 1 << 5 // May not be overridden. Note that java final implies much more than scala final. + inline val PRIVATE = 1 << 2 + inline val PROTECTED = 1 << 0 - final val SEALED = 1 << 10 - final val OVERRIDE = 1 << 1 - final val CASE = 1 << 11 - final val ABSTRACT = 1 << 3 // abstract class, or used in conjunction with abstract override. + inline val SEALED = 1 << 10 + inline val OVERRIDE = 1 << 1 + inline val CASE = 1 << 11 + inline val ABSTRACT = 1 << 3 // abstract class, or used in conjunction with abstract override. // Note difference to DEFERRED! - final val DEFERRED = 1 << 4 // was `abstract' for members | trait is virtual - final val INTERFACE = 1 << 7 // symbol is an interface (i.e. a trait which defines only abstract methods) - final val MUTABLE = 1 << 12 // symbol is a mutable variable. - final val PARAM = 1 << 13 // symbol is a (value or type) parameter to a method - final val MACRO = 1 << 15 // symbol is a macro definition + inline val DEFERRED = 1 << 4 // was `abstract' for members | trait is virtual + inline val INTERFACE = 1 << 7 // symbol is an interface (i.e. a trait which defines only abstract methods) + inline val MUTABLE = 1 << 12 // symbol is a mutable variable. + inline val PARAM = 1 << 13 // symbol is a (value or type) parameter to a method + inline val MACRO = 1 << 15 // symbol is a macro definition - final val COVARIANT = 1 << 16 // symbol is a covariant type variable - final val BYNAMEPARAM = 1 << 16 // parameter is by name - final val CONTRAVARIANT = 1 << 17 // symbol is a contravariant type variable - final val ABSOVERRIDE = 1 << 18 // combination of abstract & override - final val LOCAL = 1 << 19 // symbol is local to current class (i.e. private[this] or protected + inline val COVARIANT = 1 << 16 // symbol is a covariant type variable + inline val BYNAMEPARAM = 1 << 16 // parameter is by name + inline val CONTRAVARIANT = 1 << 17 // symbol is a contravariant type variable + inline val ABSOVERRIDE = 1 << 18 // combination of abstract & override + inline val LOCAL = 1 << 19 // symbol is local to current class (i.e. private[this] or protected // pre: PRIVATE or PROTECTED are also set - final val JAVA = 1 << 20 // symbol was defined by a Java class - final val STATIC = 1 << 23 // static field, method or class - final val CASEACCESSOR = 1 << 24 // symbol is a case parameter (or its accessor, or a GADT skolem) - final val TRAIT = 1 << 25 // symbol is a trait - final val DEFAULTPARAM = 1 << 25 // the parameter has a default value - final val PARAMACCESSOR = 1 << 29 // for field definitions generated for primary constructor + inline val JAVA = 1 << 20 // symbol was defined by a Java class + inline val STATIC = 1 << 23 // static field, method or class + inline val CASEACCESSOR = 1 << 24 // symbol is a case parameter (or its accessor, or a GADT skolem) + inline val TRAIT = 1 << 25 // symbol is a trait + inline val DEFAULTPARAM = 1 << 25 // the parameter has a default value + inline val PARAMACCESSOR = 1 << 29 // for field definitions generated for primary constructor // parameters (no matter if it's a 'val' parameter or not) // for parameters of a primary constructor ('val' or not) // for the accessor methods generated for 'val' or 'var' parameters - final val LAZY = 1L << 31 // symbol is a lazy val. can't have MUTABLE unless transformed by typer - final val PRESUPER = 1L << 37 // value is evaluated before super call - final val DEFAULTINIT = 1L << 41 // symbol is initialized to the default value: used by -Xcheckinit - final val ARTIFACT = 1L << 46 // symbol should be ignored when typechecking; will be marked ACC_SYNTHETIC in bytecode + inline val LAZY = 1L << 31 // symbol is a lazy val. can't have MUTABLE unless transformed by typer + inline val PRESUPER = 1L << 37 // value is evaluated before super call + inline val DEFAULTINIT = 1L << 41 // symbol is initialized to the default value: used by -Xcheckinit + inline val ARTIFACT = 1L << 46 // symbol should be ignored when typechecking; will be marked ACC_SYNTHETIC in bytecode // to see which symbols are marked as ARTIFACT, see scaladocs for FlagValues.ARTIFACT - final val DEFAULTMETHOD = 1L << 47 // symbol is a java default method - final val ENUM = 1L << 48 // symbol is an enum + inline val DEFAULTMETHOD = 1L << 47 // symbol is a java default method + inline val ENUM = 1L << 48 // symbol is an enum - final val PrivateLocal = PRIVATE | LOCAL - final val ProtectedLocal = PROTECTED | LOCAL - final val AccessFlags = PRIVATE | PROTECTED | LOCAL + inline val PrivateLocal = PRIVATE | LOCAL + inline val ProtectedLocal = PROTECTED | LOCAL + inline val AccessFlags = PRIVATE | PROTECTED | LOCAL - final val METHOD = 1 << 6 // a method - final val MODULE = 1 << 8 // symbol is module or class implementing a module - final val PACKAGE = 1 << 14 // symbol is a java package + inline val METHOD = 1 << 6 // a method + inline val MODULE = 1 << 8 // symbol is module or class implementing a module + inline val PACKAGE = 1 << 14 // symbol is a java package - final val CAPTURED = 1 << 16 // variable is accessed from nested function. Set by LambdaLift. - final val LABEL = 1 << 17 // method symbol is a label. Set by TailCall - final val INCONSTRUCTOR = 1 << 17 // class symbol is defined in this/superclass constructor. - final val SYNTHETIC = 1 << 21 // symbol is compiler-generated (compare with ARTIFACT) - final val STABLE = 1 << 22 // functions that are assumed to be stable + inline val CAPTURED = 1 << 16 // variable is accessed from nested function. Set by LambdaLift. + inline val LABEL = 1 << 17 // method symbol is a label. Set by TailCall + inline val INCONSTRUCTOR = 1 << 17 // class symbol is defined in this/superclass constructor. + inline val SYNTHETIC = 1 << 21 // symbol is compiler-generated (compare with ARTIFACT) + inline val STABLE = 1 << 22 // functions that are assumed to be stable // (typically, access methods for valdefs) // or classes that do not contain abstract types. - final val BRIDGE = 1 << 26 // function is a bridge method. Set by Erasure - final val ACCESSOR = 1 << 27 // a value or variable accessor (getter or setter) + inline val BRIDGE = 1 << 26 // function is a bridge method. Set by Erasure + inline val ACCESSOR = 1 << 27 // a value or variable accessor (getter or setter) - final val SUPERACCESSOR = 1 << 28 // a super accessor - final val MODULEVAR = 1 << 30 // for variables: is the variable caching a module value + inline val SUPERACCESSOR = 1 << 28 // a super accessor + inline val MODULEVAR = 1 << 30 // for variables: is the variable caching a module value - final val IS_ERROR = 1L << 32 // symbol is an error symbol - final val OVERLOADED = 1L << 33 // symbol is overloaded - final val LIFTED = 1L << 34 // class has been lifted out to package level + inline val IS_ERROR = 1L << 32 // symbol is an error symbol + inline val OVERLOADED = 1L << 33 // symbol is overloaded + inline val LIFTED = 1L << 34 // class has been lifted out to package level // local value has been lifted out to class level // todo: make LIFTED = latePRIVATE? - final val MIXEDIN = 1L << 35 // term member has been mixed in - final val EXISTENTIAL = 1L << 35 // type is an existential parameter or skolem - final val EXPANDEDNAME = 1L << 36 // name has been expanded with class suffix - final val TRANS_FLAG = 1L << 38 // transient flag guaranteed to be reset after each phase. + inline val MIXEDIN = 1L << 35 // term member has been mixed in + inline val EXISTENTIAL = 1L << 35 // type is an existential parameter or skolem + inline val EXPANDEDNAME = 1L << 36 // name has been expanded with class suffix + inline val TRANS_FLAG = 1L << 38 // transient flag guaranteed to be reset after each phase. - final val LOCKED = 1L << 39 // temporary flag to catch cyclic dependencies - final val SPECIALIZED = 1L << 40 // symbol is a generated specialized member - final val VBRIDGE = 1L << 42 // symbol is a varargs bridge + inline val LOCKED = 1L << 39 // temporary flag to catch cyclic dependencies + inline val SPECIALIZED = 1L << 40 // symbol is a generated specialized member + inline val VBRIDGE = 1L << 42 // symbol is a varargs bridge - final val VARARGS = 1L << 43 // symbol is a Java-style varargs method - final val TRIEDCOOKING = 1L << 44 // `Cooking` has been tried on this symbol + inline val VARARGS = 1L << 43 // symbol is a Java-style varargs method + inline val TRIEDCOOKING = 1L << 44 // `Cooking` has been tried on this symbol // A Java method's type is `cooked` by transforming raw types to existentials - final val SYNCHRONIZED = 1L << 45 // symbol is a method which should be marked ACC_SYNCHRONIZED + inline val SYNCHRONIZED = 1L << 45 // symbol is a method which should be marked ACC_SYNCHRONIZED - final val IMPLICIT_PKL = (1 << 0) - final val FINAL_PKL = (1 << 1) - final val PRIVATE_PKL = (1 << 2) - final val PROTECTED_PKL = (1 << 3) - final val SEALED_PKL = (1 << 4) - final val OVERRIDE_PKL = (1 << 5) - final val CASE_PKL = (1 << 6) - final val ABSTRACT_PKL = (1 << 7) - final val DEFERRED_PKL = (1 << 8) - final val METHOD_PKL = (1 << 9) - final val MODULE_PKL = (1 << 10) - final val INTERFACE_PKL = (1 << 11) + inline val IMPLICIT_PKL = (1 << 0) + inline val FINAL_PKL = (1 << 1) + inline val PRIVATE_PKL = (1 << 2) + inline val PROTECTED_PKL = (1 << 3) + inline val SEALED_PKL = (1 << 4) + inline val OVERRIDE_PKL = (1 << 5) + inline val CASE_PKL = (1 << 6) + inline val ABSTRACT_PKL = (1 << 7) + inline val DEFERRED_PKL = (1 << 8) + inline val METHOD_PKL = (1 << 9) + inline val MODULE_PKL = (1 << 10) + inline val INTERFACE_PKL = (1 << 11) } diff --git a/compiler/src/dotty/tools/dotc/parsing/JavaTokens.scala b/compiler/src/dotty/tools/dotc/parsing/JavaTokens.scala index 5c333f8646e5..3e73b6d95adb 100644 --- a/compiler/src/dotty/tools/dotc/parsing/JavaTokens.scala +++ b/compiler/src/dotty/tools/dotc/parsing/JavaTokens.scala @@ -5,7 +5,7 @@ package parsing import collection.immutable.BitSet object JavaTokens extends TokensCommon { - final val minToken = EMPTY + inline val minToken = EMPTY final def maxToken: Int = DOUBLE final val javaOnlyKeywords: TokenSet = tokenRange(INSTANCEOF, ASSERT) @@ -15,78 +15,78 @@ object JavaTokens extends TokensCommon { final val keywords: BitSet = sharedKeywords | javaOnlyKeywords | primTypes /** keywords */ - final val INSTANCEOF = 101; enter(INSTANCEOF, "instanceof") - final val CONST = 102; enter(CONST, "const") + inline val INSTANCEOF = 101; enter(INSTANCEOF, "instanceof") + inline val CONST = 102; enter(CONST, "const") /** templates */ - final val INTERFACE = 105; enter(INTERFACE, "interface") - final val ENUM = 106; enter(ENUM, "enum") - final val IMPLEMENTS = 107; enter(IMPLEMENTS, "implements") + inline val INTERFACE = 105; enter(INTERFACE, "interface") + inline val ENUM = 106; enter(ENUM, "enum") + inline val IMPLEMENTS = 107; enter(IMPLEMENTS, "implements") /** modifiers */ - final val PUBLIC = 110; enter(PUBLIC, "public") - final val DEFAULT = 111; enter(DEFAULT, "default") - final val STATIC = 112; enter(STATIC, "static") - final val TRANSIENT = 113; enter(TRANSIENT, "transient") - final val VOLATILE = 114; enter(VOLATILE, "volatile") - final val SYNCHRONIZED = 115; enter(SYNCHRONIZED, "synchronized") - final val NATIVE = 116; enter(NATIVE, "native") - final val STRICTFP = 117; enter(STRICTFP, "strictfp") - final val THROWS = 118; enter(THROWS, "throws") + inline val PUBLIC = 110; enter(PUBLIC, "public") + inline val DEFAULT = 111; enter(DEFAULT, "default") + inline val STATIC = 112; enter(STATIC, "static") + inline val TRANSIENT = 113; enter(TRANSIENT, "transient") + inline val VOLATILE = 114; enter(VOLATILE, "volatile") + inline val SYNCHRONIZED = 115; enter(SYNCHRONIZED, "synchronized") + inline val NATIVE = 116; enter(NATIVE, "native") + inline val STRICTFP = 117; enter(STRICTFP, "strictfp") + inline val THROWS = 118; enter(THROWS, "throws") /** control structures */ - final val BREAK = 130; enter(BREAK, "break") - final val CONTINUE = 131; enter(CONTINUE, "continue") - final val GOTO = 132; enter(GOTO, "goto") - final val SWITCH = 133; enter(SWITCH, "switch") - final val ASSERT = 134; enter(ASSERT, "assert") + inline val BREAK = 130; enter(BREAK, "break") + inline val CONTINUE = 131; enter(CONTINUE, "continue") + inline val GOTO = 132; enter(GOTO, "goto") + inline val SWITCH = 133; enter(SWITCH, "switch") + inline val ASSERT = 134; enter(ASSERT, "assert") /** special symbols */ - final val EQEQ = 140 - final val BANGEQ = 141 - final val LT = 142 - final val GT = 143 - final val LTEQ = 144 - final val GTEQ = 145 - final val BANG = 146 - final val QMARK = 147 - final val AMP = 148 - final val BAR = 149 - final val PLUS = 150 - final val MINUS = 151 - final val ASTERISK = 152 - final val SLASH = 153 - final val PERCENT = 154 - final val HAT = 155 - final val LTLT = 156 - final val GTGT = 157 - final val GTGTGT = 158 - final val AMPAMP = 159 - final val BARBAR = 160 - final val PLUSPLUS = 161 - final val MINUSMINUS = 162 - final val TILDE = 163 - final val DOTDOTDOT = 164 - final val AMPEQ = 165 - final val BAREQ = 166 - final val PLUSEQ = 167 - final val MINUSEQ = 168 - final val ASTERISKEQ = 169 - final val SLASHEQ = 170 - final val PERCENTEQ = 171 - final val HATEQ = 172 - final val LTLTEQ = 173 - final val GTGTEQ = 174 - final val GTGTGTEQ = 175 + inline val EQEQ = 140 + inline val BANGEQ = 141 + inline val LT = 142 + inline val GT = 143 + inline val LTEQ = 144 + inline val GTEQ = 145 + inline val BANG = 146 + inline val QMARK = 147 + inline val AMP = 148 + inline val BAR = 149 + inline val PLUS = 150 + inline val MINUS = 151 + inline val ASTERISK = 152 + inline val SLASH = 153 + inline val PERCENT = 154 + inline val HAT = 155 + inline val LTLT = 156 + inline val GTGT = 157 + inline val GTGTGT = 158 + inline val AMPAMP = 159 + inline val BARBAR = 160 + inline val PLUSPLUS = 161 + inline val MINUSMINUS = 162 + inline val TILDE = 163 + inline val DOTDOTDOT = 164 + inline val AMPEQ = 165 + inline val BAREQ = 166 + inline val PLUSEQ = 167 + inline val MINUSEQ = 168 + inline val ASTERISKEQ = 169 + inline val SLASHEQ = 170 + inline val PERCENTEQ = 171 + inline val HATEQ = 172 + inline val LTLTEQ = 173 + inline val GTGTEQ = 174 + inline val GTGTGTEQ = 175 /** primitive types */ - final val VOID = 180; enter(VOID, "void") - final val BOOLEAN = 181; enter(BOOLEAN, "boolean") - final val BYTE = 182; enter(BYTE, "byte") - final val SHORT = 183; enter(SHORT, "short") - final val CHAR = 184; enter(CHAR, "char") - final val INT = 185; enter(INT, "int") - final val LONG = 186; enter(LONG, "long") - final val FLOAT = 187; enter(FLOAT, "float") - final val DOUBLE = 188; enter(DOUBLE, "double") + inline val VOID = 180; enter(VOID, "void") + inline val BOOLEAN = 181; enter(BOOLEAN, "boolean") + inline val BYTE = 182; enter(BYTE, "byte") + inline val SHORT = 183; enter(SHORT, "short") + inline val CHAR = 184; enter(CHAR, "char") + inline val INT = 185; enter(INT, "int") + inline val LONG = 186; enter(LONG, "long") + inline val FLOAT = 187; enter(FLOAT, "float") + inline val DOUBLE = 188; enter(DOUBLE, "double") } diff --git a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala index cba07a6e5a34..55f428cef5a4 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala @@ -30,107 +30,107 @@ abstract class TokensCommon { } /** special tokens */ - final val EMPTY = 0; enter(EMPTY, "") // a missing token, used in lookahead - final val ERROR = 1; enter(ERROR, "erroneous token") // an erroneous token - final val EOF = 2; enter(EOF, "eof") + inline val EMPTY = 0; enter(EMPTY, "") // a missing token, used in lookahead + inline val ERROR = 1; enter(ERROR, "erroneous token") // an erroneous token + inline val EOF = 2; enter(EOF, "eof") /** literals */ - final val CHARLIT = 3; enter(CHARLIT, "character literal") - final val INTLIT = 4; enter(INTLIT, "integer literal") - final val DECILIT = 5; enter(DECILIT, "number literal") // with decimal point - final val EXPOLIT = 6; enter(EXPOLIT, "number literal with exponent") - final val LONGLIT = 7; enter(LONGLIT, "long literal") - final val FLOATLIT = 8; enter(FLOATLIT, "float literal") - final val DOUBLELIT = 9; enter(DOUBLELIT, "double literal") - final val STRINGLIT = 10; enter(STRINGLIT, "string literal") - final val STRINGPART = 11; enter(STRINGPART, "string literal", "string literal part") - //final val INTERPOLATIONID = 12; enter(INTERPOLATIONID, "string interpolator") - //final val QUOTEID = 13; enter(QUOTEID, "quoted identifier") // TODO: deprecate + inline val CHARLIT = 3; enter(CHARLIT, "character literal") + inline val INTLIT = 4; enter(INTLIT, "integer literal") + inline val DECILIT = 5; enter(DECILIT, "number literal") // with decimal point + inline val EXPOLIT = 6; enter(EXPOLIT, "number literal with exponent") + inline val LONGLIT = 7; enter(LONGLIT, "long literal") + inline val FLOATLIT = 8; enter(FLOATLIT, "float literal") + inline val DOUBLELIT = 9; enter(DOUBLELIT, "double literal") + inline val STRINGLIT = 10; enter(STRINGLIT, "string literal") + inline val STRINGPART = 11; enter(STRINGPART, "string literal", "string literal part") + //inline val INTERPOLATIONID = 12; enter(INTERPOLATIONID, "string interpolator") + //inline val QUOTEID = 13; enter(QUOTEID, "quoted identifier") // TODO: deprecate /** identifiers */ - final val IDENTIFIER = 14; enter(IDENTIFIER, "identifier") - //final val BACKQUOTED_IDENT = 15; enter(BACKQUOTED_IDENT, "identifier", "backquoted ident") + inline val IDENTIFIER = 14; enter(IDENTIFIER, "identifier") + //inline val BACKQUOTED_IDENT = 15; enter(BACKQUOTED_IDENT, "identifier", "backquoted ident") /** alphabetic keywords */ - final val IF = 20; enter(IF, "if") - final val FOR = 21; enter(FOR, "for") - final val ELSE = 22; enter(ELSE, "else") - final val THIS = 23; enter(THIS, "this") - final val NULL = 24; enter(NULL, "null") - final val NEW = 25; enter(NEW, "new") - //final val WITH = 26; enter(WITH, "with") - final val SUPER = 27; enter(SUPER, "super") - //final val CASE = 28; enter(CASE, "case") - //final val CASECLASS = 29; enter(CASECLASS, "case class") - //final val CASEOBJECT = 30; enter(CASEOBJECT, "case object") - //final val VAL = 31; enter(VAL, "val") - final val ABSTRACT = 32; enter(ABSTRACT, "abstract") - final val FINAL = 33; enter(FINAL, "final") - final val PRIVATE = 34; enter(PRIVATE, "private") - final val PROTECTED = 35; enter(PROTECTED, "protected") - final val OVERRIDE = 36; enter(OVERRIDE, "override") - //final val IMPLICIT = 37; enter(IMPLICIT, "implicit") - //final val VAR = 38; enter(VAR, "var") - //final val DEF = 39; enter(DEF, "def") - //final val TYPE = 40; enter(TYPE, "type") - final val EXTENDS = 41; enter(EXTENDS, "extends") - final val TRUE = 42; enter(TRUE, "true") - final val FALSE = 43; enter(FALSE, "false") - //final val OBJECT = 44; enter(OBJECT, "object") - final val CLASS = 45; enter(CLASS, "class") - final val IMPORT = 46; enter(IMPORT, "import") - final val PACKAGE = 47; enter(PACKAGE, "package") - //final val YIELD = 48; enter(YIELD, "yield") - final val DO = 49; enter(DO, "do") - //final val TRAIT = 50; enter(TRAIT, "trait") - //final val SEALED = 51; enter(SEALED, "sealed") - final val THROW = 52; enter(THROW, "throw") - final val TRY = 53; enter(TRY, "try") - final val CATCH = 54; enter(CATCH, "catch") - final val FINALLY = 55; enter(FINALLY, "finally") - final val WHILE = 56; enter(WHILE, "while") - final val RETURN = 57; enter(RETURN, "return") - //final val MATCH = 58; enter(MATCH, "match") - //final val LAZY = 59; enter(LAZY, "lazy") - //final val THEN = 60; enter(THEN, "then") - //final val FORSOME = 61; enter(FORSOME, "forSome") // TODO: deprecate - //final val ENUM = 62; enter(ENUM, "enum") + inline val IF = 20; enter(IF, "if") + inline val FOR = 21; enter(FOR, "for") + inline val ELSE = 22; enter(ELSE, "else") + inline val THIS = 23; enter(THIS, "this") + inline val NULL = 24; enter(NULL, "null") + inline val NEW = 25; enter(NEW, "new") + //inline val WITH = 26; enter(WITH, "with") + inline val SUPER = 27; enter(SUPER, "super") + //inline val CASE = 28; enter(CASE, "case") + //inline val CASECLASS = 29; enter(CASECLASS, "case class") + //inline val CASEOBJECT = 30; enter(CASEOBJECT, "case object") + //inline val VAL = 31; enter(VAL, "val") + inline val ABSTRACT = 32; enter(ABSTRACT, "abstract") + inline val FINAL = 33; enter(FINAL, "final") + inline val PRIVATE = 34; enter(PRIVATE, "private") + inline val PROTECTED = 35; enter(PROTECTED, "protected") + inline val OVERRIDE = 36; enter(OVERRIDE, "override") + //inline val IMPLICIT = 37; enter(IMPLICIT, "implicit") + //inline val VAR = 38; enter(VAR, "var") + //inline val DEF = 39; enter(DEF, "def") + //inline val TYPE = 40; enter(TYPE, "type") + inline val EXTENDS = 41; enter(EXTENDS, "extends") + inline val TRUE = 42; enter(TRUE, "true") + inline val FALSE = 43; enter(FALSE, "false") + //inline val OBJECT = 44; enter(OBJECT, "object") + inline val CLASS = 45; enter(CLASS, "class") + inline val IMPORT = 46; enter(IMPORT, "import") + inline val PACKAGE = 47; enter(PACKAGE, "package") + //inline val YIELD = 48; enter(YIELD, "yield") + inline val DO = 49; enter(DO, "do") + //inline val TRAIT = 50; enter(TRAIT, "trait") + //inline val SEALED = 51; enter(SEALED, "sealed") + inline val THROW = 52; enter(THROW, "throw") + inline val TRY = 53; enter(TRY, "try") + inline val CATCH = 54; enter(CATCH, "catch") + inline val FINALLY = 55; enter(FINALLY, "finally") + inline val WHILE = 56; enter(WHILE, "while") + inline val RETURN = 57; enter(RETURN, "return") + //inline val MATCH = 58; enter(MATCH, "match") + //inline val LAZY = 59; enter(LAZY, "lazy") + //inline val THEN = 60; enter(THEN, "then") + //inline val FORSOME = 61; enter(FORSOME, "forSome") // TODO: deprecate + //inline val ENUM = 62; enter(ENUM, "enum") /** special symbols */ - final val COMMA = 70; enter(COMMA, "','") - final val SEMI = 71; enter(SEMI, "';'") - final val DOT = 72; enter(DOT, "'.'") - //final val NEWLINE = 78; enter(NEWLINE, "end of statement", "new line") - //final val NEWLINES = 79; enter(NEWLINES, "end of statement", "new lines") + inline val COMMA = 70; enter(COMMA, "','") + inline val SEMI = 71; enter(SEMI, "';'") + inline val DOT = 72; enter(DOT, "'.'") + //inline val NEWLINE = 78; enter(NEWLINE, "end of statement", "new line") + //inline val NEWLINES = 79; enter(NEWLINES, "end of statement", "new lines") /** special keywords */ - //final val USCORE = 73; enter(USCORE, "_") - final val COLON = 74; enter(COLON, ":") - final val EQUALS = 75; enter(EQUALS, "=") - //final val LARROW = 76; enter(LARROW, "<-") - //final val ARROW = 77; enter(ARROW, "=>") - //final val SUBTYPE = 80; enter(SUBTYPE, "<:") - //final val SUPERTYPE = 81; enter(SUPERTYPE, ">:") - //final val HASH = 82; enter(HASH, "#") - final val AT = 83; enter(AT, "@") - //final val VIEWBOUND = 84; enter(VIEWBOUND, "<%") + //inline val USCORE = 73; enter(USCORE, "_") + inline val COLON = 74; enter(COLON, ":") + inline val EQUALS = 75; enter(EQUALS, "=") + //inline val LARROW = 76; enter(LARROW, "<-") + //inline val ARROW = 77; enter(ARROW, "=>") + //inline val SUBTYPE = 80; enter(SUBTYPE, "<:") + //inline val SUPERTYPE = 81; enter(SUPERTYPE, ">:") + //inline val HASH = 82; enter(HASH, "#") + inline val AT = 83; enter(AT, "@") + //inline val VIEWBOUND = 84; enter(VIEWBOUND, "<%") val keywords: TokenSet def isKeyword(token: Token): Boolean = keywords contains token /** parentheses */ - final val LPAREN = 91; enter(LPAREN, "'('") - final val RPAREN = 92; enter(RPAREN, "')'") - final val LBRACKET = 93; enter(LBRACKET, "'['") - final val RBRACKET = 94; enter(RBRACKET, "']'") - final val LBRACE = 95; enter(LBRACE, "'{'") - final val RBRACE = 96; enter(RBRACE, "'}'") - final val INDENT = 97; enter(INDENT, "indent") - final val OUTDENT = 98; enter(OUTDENT, "unindent") - - final val firstParen = LPAREN - final val lastParen = OUTDENT + inline val LPAREN = 91; enter(LPAREN, "'('") + inline val RPAREN = 92; enter(RPAREN, "')'") + inline val LBRACKET = 93; enter(LBRACKET, "'['") + inline val RBRACKET = 94; enter(RBRACKET, "']'") + inline val LBRACE = 95; enter(LBRACE, "'{'") + inline val RBRACE = 96; enter(RBRACE, "'}'") + inline val INDENT = 97; enter(INDENT, "indent") + inline val OUTDENT = 98; enter(OUTDENT, "unindent") + + inline val firstParen = LPAREN + inline val lastParen = OUTDENT def buildKeywordArray(keywords: TokenSet): (Int, Array[Int]) = { def start(tok: Token) = tokenString(tok).toTermName.asSimpleName.start @@ -148,13 +148,13 @@ abstract class TokensCommon { } object Tokens extends TokensCommon { - final val minToken = EMPTY + inline val minToken = EMPTY final def maxToken: Int = XMLSTART - final val INTERPOLATIONID = 12; enter(INTERPOLATIONID, "string interpolator") - final val QUOTEID = 13; enter(QUOTEID, "quoted identifier") // TODO: deprecate + inline val INTERPOLATIONID = 12; enter(INTERPOLATIONID, "string interpolator") + inline val QUOTEID = 13; enter(QUOTEID, "quoted identifier") // TODO: deprecate - final val BACKQUOTED_IDENT = 15; enter(BACKQUOTED_IDENT, "identifier", "backquoted ident") + inline val BACKQUOTED_IDENT = 15; enter(BACKQUOTED_IDENT, "identifier", "backquoted ident") final val identifierTokens: TokenSet = BitSet(IDENTIFIER, BACKQUOTED_IDENT) @@ -162,51 +162,51 @@ object Tokens extends TokensCommon { token >= IDENTIFIER && token <= BACKQUOTED_IDENT /** alphabetic keywords */ - final val WITH = 26; enter(WITH, "with") - final val CASE = 28; enter(CASE, "case") - final val CASECLASS = 29; enter(CASECLASS, "case class") - final val CASEOBJECT = 30; enter(CASEOBJECT, "case object") - final val VAL = 31; enter(VAL, "val") - final val IMPLICIT = 37; enter(IMPLICIT, "implicit") - final val VAR = 38; enter(VAR, "var") - final val DEF = 39; enter(DEF, "def") - final val TYPE = 40; enter(TYPE, "type") - final val OBJECT = 44; enter(OBJECT, "object") - final val YIELD = 48; enter(YIELD, "yield") - final val TRAIT = 50; enter(TRAIT, "trait") - final val SEALED = 51; enter(SEALED, "sealed") - final val MATCH = 58; enter(MATCH, "match") - final val LAZY = 59; enter(LAZY, "lazy") - final val THEN = 60; enter(THEN, "then") - final val FORSOME = 61; enter(FORSOME, "forSome") // TODO: deprecate - final val ENUM = 62; enter(ENUM, "enum") - final val GIVEN = 63; enter(GIVEN, "given") - final val EXPORT = 64; enter(EXPORT, "export") - final val MACRO = 65; enter(MACRO, "macro") // TODO: remove - final val END = 66; enter(END, "end") + inline val WITH = 26; enter(WITH, "with") + inline val CASE = 28; enter(CASE, "case") + inline val CASECLASS = 29; enter(CASECLASS, "case class") + inline val CASEOBJECT = 30; enter(CASEOBJECT, "case object") + inline val VAL = 31; enter(VAL, "val") + inline val IMPLICIT = 37; enter(IMPLICIT, "implicit") + inline val VAR = 38; enter(VAR, "var") + inline val DEF = 39; enter(DEF, "def") + inline val TYPE = 40; enter(TYPE, "type") + inline val OBJECT = 44; enter(OBJECT, "object") + inline val YIELD = 48; enter(YIELD, "yield") + inline val TRAIT = 50; enter(TRAIT, "trait") + inline val SEALED = 51; enter(SEALED, "sealed") + inline val MATCH = 58; enter(MATCH, "match") + inline val LAZY = 59; enter(LAZY, "lazy") + inline val THEN = 60; enter(THEN, "then") + inline val FORSOME = 61; enter(FORSOME, "forSome") // TODO: deprecate + inline val ENUM = 62; enter(ENUM, "enum") + inline val GIVEN = 63; enter(GIVEN, "given") + inline val EXPORT = 64; enter(EXPORT, "export") + inline val MACRO = 65; enter(MACRO, "macro") // TODO: remove + inline val END = 66; enter(END, "end") /** special symbols */ - final val NEWLINE = 78; enter(NEWLINE, "end of statement", "new line") - final val NEWLINES = 79; enter(NEWLINES, "end of statement", "new lines") + inline val NEWLINE = 78; enter(NEWLINE, "end of statement", "new line") + inline val NEWLINES = 79; enter(NEWLINES, "end of statement", "new lines") /** special keywords */ - final val USCORE = 73; enter(USCORE, "_") - final val LARROW = 76; enter(LARROW, "<-") - final val ARROW = 77; enter(ARROW, "=>") - final val SUBTYPE = 80; enter(SUBTYPE, "<:") - final val SUPERTYPE = 81; enter(SUPERTYPE, ">:") - final val HASH = 82; enter(HASH, "#") - final val VIEWBOUND = 84; enter(VIEWBOUND, "<%") - final val TLARROW = 85; enter(TLARROW, "=>>") - final val CTXARROW = 86; enter(CTXARROW, "?=>") + inline val USCORE = 73; enter(USCORE, "_") + inline val LARROW = 76; enter(LARROW, "<-") + inline val ARROW = 77; enter(ARROW, "=>") + inline val SUBTYPE = 80; enter(SUBTYPE, "<:") + inline val SUPERTYPE = 81; enter(SUPERTYPE, ">:") + inline val HASH = 82; enter(HASH, "#") + inline val VIEWBOUND = 84; enter(VIEWBOUND, "<%") + inline val TLARROW = 85; enter(TLARROW, "=>>") + inline val CTXARROW = 86; enter(CTXARROW, "?=>") - final val QUOTE = 87; enter(QUOTE, "'") + inline val QUOTE = 87; enter(QUOTE, "'") - final val COLONEOL = 88; enter(COLONEOL, ":", ": at eol") - final val SELFARROW = 89; enter(SELFARROW, "=>") // reclassified ARROW following self-type + inline val COLONEOL = 88; enter(COLONEOL, ":", ": at eol") + inline val SELFARROW = 89; enter(SELFARROW, "=>") // reclassified ARROW following self-type /** XML mode */ - final val XMLSTART = 99; enter(XMLSTART, "$XMLSTART$<") // TODO: deprecate + inline val XMLSTART = 99; enter(XMLSTART, "$XMLSTART$<") // TODO: deprecate final val alphaKeywords: TokenSet = tokenRange(IF, END) final val symbolicKeywords: TokenSet = tokenRange(USCORE, CTXARROW) diff --git a/compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala b/compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala index cce2c6d00859..623f540bd721 100644 --- a/compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala +++ b/compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala @@ -17,7 +17,7 @@ import java.util.Arrays object SyntaxHighlighting { /** if true, log erroneous positions being highlighted */ - private final val debug = true + private inline val debug = true // Keep in sync with SyntaxHighlightingTests val NoColor: String = Console.RESET diff --git a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala index 5a640c8f1d98..7546c1fd854d 100644 --- a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -54,10 +54,10 @@ object PatternMatcher { val name: String = "patternMatcher" - final val selfCheck = false // debug option, if on we check that no case gets generated twice + inline val selfCheck = false // debug option, if on we check that no case gets generated twice /** Minimal number of cases to emit a switch */ - final val MinSwitchCases = 4 + inline val MinSwitchCases = 4 val TrustedTypeTestKey: Key[Unit] = new StickyKey[Unit] diff --git a/compiler/src/dotty/tools/dotc/transform/sjs/JSExportUtils.scala b/compiler/src/dotty/tools/dotc/transform/sjs/JSExportUtils.scala index 6825ddcc1fef..57e5fc636ddc 100644 --- a/compiler/src/dotty/tools/dotc/transform/sjs/JSExportUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/sjs/JSExportUtils.scala @@ -26,9 +26,9 @@ import dotty.tools.backend.sjs.JSDefinitions.jsdefn /** Utilities for JS exports handling. */ object JSExportUtils { - private final val ExportPrefix = "$js$exported$" - private final val MethodExportPrefix = ExportPrefix + "meth$" - private final val PropExportPrefix = ExportPrefix + "prop$" + private inline val ExportPrefix = "$js$exported$" + private inline val MethodExportPrefix = ExportPrefix + "meth$" + private inline val PropExportPrefix = ExportPrefix + "prop$" /** Creates a name for an export specification. */ def makeExportName(jsName: String, isProp: Boolean): TermName = { diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index a3b0dd02714d..d7bf75f8bf73 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -66,10 +66,10 @@ object Implicits: } object Candidate { type Kind = Int - final val None = 0 - final val Value = 1 - final val Conversion = 2 - final val Extension = 4 + inline val None = 0 + inline val Value = 1 + inline val Conversion = 2 + inline val Extension = 4 } /** If `expected` is a selection prototype, does `tp` have an extension diff --git a/compiler/src/dotty/tools/dotc/util/Chars.scala b/compiler/src/dotty/tools/dotc/util/Chars.scala index 986b1fda58ec..4c54dc73459e 100644 --- a/compiler/src/dotty/tools/dotc/util/Chars.scala +++ b/compiler/src/dotty/tools/dotc/util/Chars.scala @@ -11,10 +11,10 @@ import java.lang.Character.UPPERCASE_LETTER /** Contains constants and classifier methods for characters */ object Chars { - final val LF = '\u000A' - final val FF = '\u000C' - final val CR = '\u000D' - final val SU = '\u001A' + inline val LF = '\u000A' + inline val FF = '\u000C' + inline val CR = '\u000D' + inline val SU = '\u001A' /** Convert a character digit to an Int according to given base, * -1 if no success diff --git a/compiler/src/dotty/tools/dotc/util/ReusableInstance.scala b/compiler/src/dotty/tools/dotc/util/ReusableInstance.scala index 16bd2decd908..4dd897dd082a 100644 --- a/compiler/src/dotty/tools/dotc/util/ReusableInstance.scala +++ b/compiler/src/dotty/tools/dotc/util/ReusableInstance.scala @@ -27,7 +27,7 @@ final class ReusableInstance[T <: AnyRef] private (make: => T) { } object ReusableInstance { - private final val InitialSize = 4 + private inline val InitialSize = 4 def apply[T <: AnyRef](make: => T): ReusableInstance[T] = new ReusableInstance[T](make) } diff --git a/compiler/src/dotty/tools/dotc/util/SixteenNibbles.scala b/compiler/src/dotty/tools/dotc/util/SixteenNibbles.scala index ebeb9f700273..42286aef5d31 100644 --- a/compiler/src/dotty/tools/dotc/util/SixteenNibbles.scala +++ b/compiler/src/dotty/tools/dotc/util/SixteenNibbles.scala @@ -22,7 +22,7 @@ class SixteenNibbles(val bits: Long) extends AnyVal { } object SixteenNibbles { - final val Width = 4 - final val Mask = (1 << Width) - 1 + inline val Width = 4 + inline val Mask = (1 << Width) - 1 final val LongMask: Long = Mask.toLong } diff --git a/compiler/src/dotty/tools/dotc/util/Spans.scala b/compiler/src/dotty/tools/dotc/util/Spans.scala index f73f1da86ce5..0a28c367ff29 100644 --- a/compiler/src/dotty/tools/dotc/util/Spans.scala +++ b/compiler/src/dotty/tools/dotc/util/Spans.scala @@ -15,9 +15,9 @@ import language.implicitConversions */ object Spans { - private final val StartEndBits = 26 - private final val StartEndMask = (1L << StartEndBits) - 1 - private final val SyntheticPointDelta = (1 << (64 - StartEndBits * 2)) - 1 + private inline val StartEndBits = 26 + private inline val StartEndMask = (1L << StartEndBits) - 1 + private inline val SyntheticPointDelta = (1 << (64 - StartEndBits * 2)) - 1 /** The maximal representable offset in a span */ final val MaxOffset = StartEndMask.toInt diff --git a/compiler/src/dotty/tools/dotc/util/Stats.scala b/compiler/src/dotty/tools/dotc/util/Stats.scala index 2de6e6554e15..60465e519452 100644 --- a/compiler/src/dotty/tools/dotc/util/Stats.scala +++ b/compiler/src/dotty/tools/dotc/util/Stats.scala @@ -9,7 +9,7 @@ import collection.mutable @sharable object Stats { - final val enabled = false + inline val enabled = false var monitored: Boolean = false @@ -43,7 +43,7 @@ import collection.mutable else op } - final val GroupChar = '/' + inline val GroupChar = '/' /** Aggregate all counts of all keys with a common prefix, followed by `:` */ private def aggregate(): Unit = { From a50070f4d4e386046bd31a8ca2b6584745224a86 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Sat, 6 Nov 2021 18:24:17 +0000 Subject: [PATCH 0848/1244] Fixes and improvements to trace logging The String.valueOf is because I somehow ended up with a null. Then I found some docs in the history of trace, as well as a mistake in a commit revert: using the non-StoreReporter logctx! I also added a "log" variant to "force", which is also default enabled but doesn't force the output to the standard out, meaning I can bootstrap the compiler without it taking forever to output all the trace output it generates while bootstrapping the compiler, bottlenecking on console IO)... Also, remove some dead code in Definitions. --- compiler/src/dotty/tools/dotc/core/Definitions.scala | 7 ------- .../src/dotty/tools/dotc/printing/Formatting.scala | 2 +- compiler/src/dotty/tools/dotc/reporting/trace.scala | 12 +++++++++++- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index d6c713039190..c5be301df8d7 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -1370,13 +1370,6 @@ class Definitions { else if arity >= 0 then FunctionType(arity) else NoType - val predefClassNames: Set[Name] = - Set("Predef$", "DeprecatedPredef", "LowPriorityImplicits").map(_.toTypeName.unmangleClassName) - - /** Is `cls` the predef module class, or a class inherited by Predef? */ - def isPredefClass(cls: Symbol): Boolean = - (cls.owner eq ScalaPackageClass) && predefClassNames.contains(cls.name) - private val JavaImportFns: List[RootRef] = List( RootRef(() => JavaLangPackageVal.termRef) ) diff --git a/compiler/src/dotty/tools/dotc/printing/Formatting.scala b/compiler/src/dotty/tools/dotc/printing/Formatting.scala index be25469c549d..845283f69a0f 100644 --- a/compiler/src/dotty/tools/dotc/printing/Formatting.scala +++ b/compiler/src/dotty/tools/dotc/printing/Formatting.scala @@ -36,7 +36,7 @@ object Formatting { case _ => ex.getMessage s"[cannot display due to $msg, raw string = ${arg.toString}]" } - case _ => arg.toString + case _ => String.valueOf(arg) } private def treatArg(arg: Any, suffix: String)(using Context): (Any, String) = arg match { diff --git a/compiler/src/dotty/tools/dotc/reporting/trace.scala b/compiler/src/dotty/tools/dotc/reporting/trace.scala index 8e111950bacc..10179f9d3789 100644 --- a/compiler/src/dotty/tools/dotc/reporting/trace.scala +++ b/compiler/src/dotty/tools/dotc/reporting/trace.scala @@ -7,6 +7,12 @@ import config.Config import config.Printers import core.Mode +/** Exposes the {{{ trace("question") { op } }}} syntax. + * + * Traced operations will print indented messages if enabled. + * Tracing depends on [[Config.tracingEnabled]] and [[dotty.tools.dotc.config.ScalaSettings.Ylog]]. + * Tracing can be forced by replacing [[trace]] with [[trace.force]] or [[trace.log]] (see below). + */ object trace extends TraceSyntax: inline def isEnabled = Config.tracingEnabled protected val isForced = false @@ -14,6 +20,10 @@ object trace extends TraceSyntax: object force extends TraceSyntax: inline def isEnabled: true = true protected val isForced = true + + object log extends TraceSyntax: + inline def isEnabled: true = true + protected val isForced = false end trace /** This module is carefully optimized to give zero overhead if Config.tracingEnabled @@ -73,7 +83,7 @@ trait TraceSyntax: var logctx = ctx while logctx.reporter.isInstanceOf[StoreReporter] do logctx = logctx.outer def margin = ctx.base.indentTab * ctx.base.indent - def doLog(s: String) = if isForced then println(s) else report.log(s) + def doLog(s: String) = if isForced then println(s) else report.log(s)(using logctx) def finalize(msg: String) = if !finalized then ctx.base.indent -= 1 From 06edfc055c46b574d8e792894741aa7d1155fa1f Mon Sep 17 00:00:00 2001 From: soronpo Date: Thu, 26 Aug 2021 13:45:35 -0400 Subject: [PATCH 0849/1244] Adds compiletime.ops.{long, float, double}, adds other ops, and fixes termref type not being considered. fix check file more ops wip Added ops.float and ops.double --- .../dotty/tools/dotc/core/Definitions.scala | 35 ++- .../src/dotty/tools/dotc/core/StdNames.scala | 55 +++-- .../src/dotty/tools/dotc/core/Types.scala | 134 ++++++++++- library/src/scala/compiletime/ops/any.scala | 19 ++ .../src/scala/compiletime/ops/double.scala | 136 +++++++++++ library/src/scala/compiletime/ops/float.scala | 136 +++++++++++ library/src/scala/compiletime/ops/int.scala | 39 +++ library/src/scala/compiletime/ops/long.scala | 222 ++++++++++++++++++ .../src/scala/compiletime/ops/string.scala | 29 +++ tests/neg/singleton-ops-any.check | 14 ++ tests/neg/singleton-ops-any.scala | 20 ++ tests/neg/singleton-ops-double.scala | 77 ++++++ tests/neg/singleton-ops-float.scala | 77 ++++++ tests/neg/singleton-ops-int.scala | 22 +- tests/neg/singleton-ops-long.scala | 113 +++++++++ tests/neg/singleton-ops-string.scala | 10 + 16 files changed, 1099 insertions(+), 39 deletions(-) create mode 100644 library/src/scala/compiletime/ops/double.scala create mode 100644 library/src/scala/compiletime/ops/float.scala create mode 100644 library/src/scala/compiletime/ops/long.scala create mode 100644 tests/neg/singleton-ops-double.scala create mode 100644 tests/neg/singleton-ops-float.scala create mode 100644 tests/neg/singleton-ops-long.scala diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index c5be301df8d7..1ee40f5d1830 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -246,6 +246,9 @@ class Definitions { @tu lazy val CompiletimeOpsPackage: Symbol = requiredPackage("scala.compiletime.ops") @tu lazy val CompiletimeOpsAnyModuleClass: Symbol = requiredModule("scala.compiletime.ops.any").moduleClass @tu lazy val CompiletimeOpsIntModuleClass: Symbol = requiredModule("scala.compiletime.ops.int").moduleClass + @tu lazy val CompiletimeOpsLongModuleClass: Symbol = requiredModule("scala.compiletime.ops.long").moduleClass + @tu lazy val CompiletimeOpsFloatModuleClass: Symbol = requiredModule("scala.compiletime.ops.float").moduleClass + @tu lazy val CompiletimeOpsDoubleModuleClass: Symbol = requiredModule("scala.compiletime.ops.double").moduleClass @tu lazy val CompiletimeOpsStringModuleClass: Symbol = requiredModule("scala.compiletime.ops.string").moduleClass @tu lazy val CompiletimeOpsBooleanModuleClass: Symbol = requiredModule("scala.compiletime.ops.boolean").moduleClass @@ -1078,19 +1081,40 @@ class Definitions { final def isCompiletime_S(sym: Symbol)(using Context): Boolean = sym.name == tpnme.S && sym.owner == CompiletimeOpsIntModuleClass - private val compiletimePackageAnyTypes: Set[Name] = Set(tpnme.Equals, tpnme.NotEquals) - private val compiletimePackageIntTypes: Set[Name] = Set( + private val compiletimePackageAnyTypes: Set[Name] = Set( + tpnme.Equals, tpnme.NotEquals, tpnme.IsConst, tpnme.ToString + ) + private val compiletimePackageNumericTypes: Set[Name] = Set( tpnme.Plus, tpnme.Minus, tpnme.Times, tpnme.Div, tpnme.Mod, tpnme.Lt, tpnme.Gt, tpnme.Ge, tpnme.Le, - tpnme.Abs, tpnme.Negate, tpnme.Min, tpnme.Max, tpnme.ToString, + tpnme.Abs, tpnme.Negate, tpnme.Min, tpnme.Max + ) + private val compiletimePackageIntTypes: Set[Name] = compiletimePackageNumericTypes ++ Set[Name]( + tpnme.ToString, //ToString is moved to ops.any and deprecated for ops.int + tpnme.NumberOfLeadingZeros, tpnme.ToLong, tpnme.ToFloat, tpnme.ToDouble, + tpnme.Xor, tpnme.BitwiseAnd, tpnme.BitwiseOr, tpnme.ASR, tpnme.LSL, tpnme.LSR + ) + private val compiletimePackageLongTypes: Set[Name] = compiletimePackageNumericTypes ++ Set[Name]( + tpnme.NumberOfLeadingZeros, tpnme.ToInt, tpnme.ToFloat, tpnme.ToDouble, tpnme.Xor, tpnme.BitwiseAnd, tpnme.BitwiseOr, tpnme.ASR, tpnme.LSL, tpnme.LSR ) + private val compiletimePackageFloatTypes: Set[Name] = compiletimePackageNumericTypes ++ Set[Name]( + tpnme.ToInt, tpnme.ToLong, tpnme.ToDouble + ) + private val compiletimePackageDoubleTypes: Set[Name] = compiletimePackageNumericTypes ++ Set[Name]( + tpnme.ToInt, tpnme.ToLong, tpnme.ToFloat + ) private val compiletimePackageBooleanTypes: Set[Name] = Set(tpnme.Not, tpnme.Xor, tpnme.And, tpnme.Or) - private val compiletimePackageStringTypes: Set[Name] = Set(tpnme.Plus) + private val compiletimePackageStringTypes: Set[Name] = Set( + tpnme.Plus, tpnme.Length, tpnme.Substring, tpnme.Matches + ) private val compiletimePackageOpTypes: Set[Name] = Set(tpnme.S) ++ compiletimePackageAnyTypes ++ compiletimePackageIntTypes + ++ compiletimePackageLongTypes + ++ compiletimePackageFloatTypes + ++ compiletimePackageDoubleTypes ++ compiletimePackageBooleanTypes ++ compiletimePackageStringTypes @@ -1100,6 +1124,9 @@ class Definitions { isCompiletime_S(sym) || sym.owner == CompiletimeOpsAnyModuleClass && compiletimePackageAnyTypes.contains(sym.name) || sym.owner == CompiletimeOpsIntModuleClass && compiletimePackageIntTypes.contains(sym.name) + || sym.owner == CompiletimeOpsLongModuleClass && compiletimePackageLongTypes.contains(sym.name) + || sym.owner == CompiletimeOpsFloatModuleClass && compiletimePackageFloatTypes.contains(sym.name) + || sym.owner == CompiletimeOpsDoubleModuleClass && compiletimePackageDoubleTypes.contains(sym.name) || sym.owner == CompiletimeOpsBooleanModuleClass && compiletimePackageBooleanTypes.contains(sym.name) || sym.owner == CompiletimeOpsStringModuleClass && compiletimePackageStringTypes.contains(sym.name) ) diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 349f80d11d8a..4988b81918df 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -211,29 +211,38 @@ object StdNames { final val IOOBException: N = "IndexOutOfBoundsException" final val FunctionXXL: N = "FunctionXXL" - final val Abs: N = "Abs" - final val And: N = "&&" - final val BitwiseAnd: N = "BitwiseAnd" - final val BitwiseOr: N = "BitwiseOr" - final val Div: N = "/" - final val Equals: N = "==" - final val Ge: N = ">=" - final val Gt: N = ">" - final val Le: N = "<=" - final val Lt: N = "<" - final val Max: N = "Max" - final val Min: N = "Min" - final val Minus: N = "-" - final val Mod: N = "%" - final val Negate: N = "Negate" - final val Not: N = "!" - final val NotEquals: N = "!=" - final val Or: N = "||" - final val Plus: N = "+" - final val S: N = "S" - final val Times: N = "*" - final val ToString: N = "ToString" - final val Xor: N = "^" + final val Abs: N = "Abs" + final val And: N = "&&" + final val BitwiseAnd: N = "BitwiseAnd" + final val BitwiseOr: N = "BitwiseOr" + final val Div: N = "/" + final val Equals: N = "==" + final val Ge: N = ">=" + final val Gt: N = ">" + final val IsConst: N = "IsConst" + final val Le: N = "<=" + final val Length: N = "Length" + final val Lt: N = "<" + final val Matches: N = "Matches" + final val Max: N = "Max" + final val Min: N = "Min" + final val Minus: N = "-" + final val Mod: N = "%" + final val Negate: N = "Negate" + final val Not: N = "!" + final val NotEquals: N = "!=" + final val NumberOfLeadingZeros: N = "NumberOfLeadingZeros" + final val Or: N = "||" + final val Plus: N = "+" + final val S: N = "S" + final val Substring: N = "Substring" + final val Times: N = "*" + final val ToInt: N = "ToInt" + final val ToLong: N = "ToLong" + final val ToFloat: N = "ToFloat" + final val ToDouble: N = "ToDouble" + final val ToString: N = "ToString" + final val Xor: N = "^" final val ClassfileAnnotation: N = "ClassfileAnnotation" final val ClassManifest: N = "ClassManifest" diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index b384cbdcb084..bb48f9c6ebc0 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -4206,37 +4206,76 @@ object Types { def tryCompiletimeConstantFold(using Context): Type = tycon match { case tycon: TypeRef if defn.isCompiletimeAppliedType(tycon.symbol) => - def constValue(tp: Type): Option[Any] = tp.dealias match { + extension (tp : Type) def fixForEvaluation : Type = + tp.normalized.dealias match { + case tp : TermRef => tp.underlying + case tp => tp + } + + def constValue(tp: Type): Option[Any] = tp.fixForEvaluation match { case ConstantType(Constant(n)) => Some(n) case _ => None } - def boolValue(tp: Type): Option[Boolean] = tp.dealias match { + def boolValue(tp: Type): Option[Boolean] = tp.fixForEvaluation match { case ConstantType(Constant(n: Boolean)) => Some(n) case _ => None } - def intValue(tp: Type): Option[Int] = tp.dealias match { + def intValue(tp: Type): Option[Int] = tp.fixForEvaluation match { case ConstantType(Constant(n: Int)) => Some(n) case _ => None } - def stringValue(tp: Type): Option[String] = tp.dealias match { - case ConstantType(Constant(n: String)) => Some(n) + def longValue(tp: Type): Option[Long] = tp.fixForEvaluation match { + case ConstantType(Constant(n: Long)) => Some(n) + case _ => None + } + + def floatValue(tp: Type): Option[Float] = tp.fixForEvaluation match { + case ConstantType(Constant(n: Float)) => Some(n) + case _ => None + } + + def doubleValue(tp: Type): Option[Double] = tp.fixForEvaluation match { + case ConstantType(Constant(n: Double)) => Some(n) case _ => None } + def stringValue(tp: Type): Option[String] = tp.fixForEvaluation match { + case ConstantType(Constant(n: String)) => Some(n) + case _ => None + } + def isConst : Option[Type] = args.head.fixForEvaluation match { + case ConstantType(_) => Some(ConstantType(Constant(true))) + case _ => Some(ConstantType(Constant(false))) + } def natValue(tp: Type): Option[Int] = intValue(tp).filter(n => n >= 0 && n < Int.MaxValue) def constantFold1[T](extractor: Type => Option[T], op: T => Any): Option[Type] = - extractor(args.head.normalized).map(a => ConstantType(Constant(op(a)))) + extractor(args.head).map(a => ConstantType(Constant(op(a)))) def constantFold2[T](extractor: Type => Option[T], op: (T, T) => Any): Option[Type] = + constantFold2AB(extractor, extractor, op) + + def constantFold2AB[TA, TB](extractorA: Type => Option[TA], extractorB: Type => Option[TB], op: (TA, TB) => Any): Option[Type] = for { - a <- extractor(args.head.normalized) - b <- extractor(args.tail.head.normalized) + a <- extractorA(args.head) + b <- extractorB(args.last) } yield ConstantType(Constant(op(a, b))) + def constantFold3[TA, TB, TC]( + extractorA: Type => Option[TA], + extractorB: Type => Option[TB], + extractorC: Type => Option[TC], + op: (TA, TB, TC) => Any + ): Option[Type] = + for { + a <- extractorA(args.head) + b <- extractorB(args(1)) + c <- extractorC(args.last) + } yield ConstantType(Constant(op(a, b, c))) + trace(i"compiletime constant fold $this", typr, show = true) { val name = tycon.symbol.name val owner = tycon.symbol.owner @@ -4248,10 +4287,13 @@ object Types { } else if (owner == defn.CompiletimeOpsAnyModuleClass) name match { case tpnme.Equals if nArgs == 2 => constantFold2(constValue, _ == _) case tpnme.NotEquals if nArgs == 2 => constantFold2(constValue, _ != _) + case tpnme.ToString if nArgs == 1 => constantFold1(constValue, _.toString) + case tpnme.IsConst if nArgs == 1 => isConst case _ => None } else if (owner == defn.CompiletimeOpsIntModuleClass) name match { case tpnme.Abs if nArgs == 1 => constantFold1(intValue, _.abs) case tpnme.Negate if nArgs == 1 => constantFold1(intValue, x => -x) + //ToString is deprecated for ops.int, and moved to ops.any case tpnme.ToString if nArgs == 1 => constantFold1(intValue, _.toString) case tpnme.Plus if nArgs == 2 => constantFold2(intValue, _ + _) case tpnme.Minus if nArgs == 2 => constantFold2(intValue, _ - _) @@ -4276,9 +4318,85 @@ object Types { case tpnme.LSR if nArgs == 2 => constantFold2(intValue, _ >>> _) case tpnme.Min if nArgs == 2 => constantFold2(intValue, _ min _) case tpnme.Max if nArgs == 2 => constantFold2(intValue, _ max _) + case tpnme.NumberOfLeadingZeros if nArgs == 1 => constantFold1(intValue, Integer.numberOfLeadingZeros(_)) + case tpnme.ToLong if nArgs == 1 => constantFold1(intValue, _.toLong) + case tpnme.ToFloat if nArgs == 1 => constantFold1(intValue, _.toFloat) + case tpnme.ToDouble if nArgs == 1 => constantFold1(intValue, _.toDouble) + case _ => None + } else if (owner == defn.CompiletimeOpsLongModuleClass) name match { + case tpnme.Abs if nArgs == 1 => constantFold1(longValue, _.abs) + case tpnme.Negate if nArgs == 1 => constantFold1(longValue, x => -x) + case tpnme.Plus if nArgs == 2 => constantFold2(longValue, _ + _) + case tpnme.Minus if nArgs == 2 => constantFold2(longValue, _ - _) + case tpnme.Times if nArgs == 2 => constantFold2(longValue, _ * _) + case tpnme.Div if nArgs == 2 => constantFold2(longValue, { + case (_, 0L) => throw new TypeError("Division by 0") + case (a, b) => a / b + }) + case tpnme.Mod if nArgs == 2 => constantFold2(longValue, { + case (_, 0L) => throw new TypeError("Modulo by 0") + case (a, b) => a % b + }) + case tpnme.Lt if nArgs == 2 => constantFold2(longValue, _ < _) + case tpnme.Gt if nArgs == 2 => constantFold2(longValue, _ > _) + case tpnme.Ge if nArgs == 2 => constantFold2(longValue, _ >= _) + case tpnme.Le if nArgs == 2 => constantFold2(longValue, _ <= _) + case tpnme.Xor if nArgs == 2 => constantFold2(longValue, _ ^ _) + case tpnme.BitwiseAnd if nArgs == 2 => constantFold2(longValue, _ & _) + case tpnme.BitwiseOr if nArgs == 2 => constantFold2(longValue, _ | _) + case tpnme.ASR if nArgs == 2 => constantFold2(longValue, _ >> _) + case tpnme.LSL if nArgs == 2 => constantFold2(longValue, _ << _) + case tpnme.LSR if nArgs == 2 => constantFold2(longValue, _ >>> _) + case tpnme.Min if nArgs == 2 => constantFold2(longValue, _ min _) + case tpnme.Max if nArgs == 2 => constantFold2(longValue, _ max _) + case tpnme.NumberOfLeadingZeros if nArgs == 1 => + constantFold1(longValue, java.lang.Long.numberOfLeadingZeros(_)) + case tpnme.ToInt if nArgs == 1 => constantFold1(longValue, _.toInt) + case tpnme.ToFloat if nArgs == 1 => constantFold1(longValue, _.toFloat) + case tpnme.ToDouble if nArgs == 1 => constantFold1(longValue, _.toDouble) + case _ => None + } else if (owner == defn.CompiletimeOpsFloatModuleClass) name match { + case tpnme.Abs if nArgs == 1 => constantFold1(floatValue, _.abs) + case tpnme.Negate if nArgs == 1 => constantFold1(floatValue, x => -x) + case tpnme.Plus if nArgs == 2 => constantFold2(floatValue, _ + _) + case tpnme.Minus if nArgs == 2 => constantFold2(floatValue, _ - _) + case tpnme.Times if nArgs == 2 => constantFold2(floatValue, _ * _) + case tpnme.Div if nArgs == 2 => constantFold2(floatValue, _ / _) + case tpnme.Mod if nArgs == 2 => constantFold2(floatValue, _ % _) + case tpnme.Lt if nArgs == 2 => constantFold2(floatValue, _ < _) + case tpnme.Gt if nArgs == 2 => constantFold2(floatValue, _ > _) + case tpnme.Ge if nArgs == 2 => constantFold2(floatValue, _ >= _) + case tpnme.Le if nArgs == 2 => constantFold2(floatValue, _ <= _) + case tpnme.Min if nArgs == 2 => constantFold2(floatValue, _ min _) + case tpnme.Max if nArgs == 2 => constantFold2(floatValue, _ max _) + case tpnme.ToInt if nArgs == 1 => constantFold1(floatValue, _.toInt) + case tpnme.ToLong if nArgs == 1 => constantFold1(floatValue, _.toLong) + case tpnme.ToDouble if nArgs == 1 => constantFold1(floatValue, _.toDouble) + case _ => None + } else if (owner == defn.CompiletimeOpsDoubleModuleClass) name match { + case tpnme.Abs if nArgs == 1 => constantFold1(doubleValue, _.abs) + case tpnme.Negate if nArgs == 1 => constantFold1(doubleValue, x => -x) + case tpnme.Plus if nArgs == 2 => constantFold2(doubleValue, _ + _) + case tpnme.Minus if nArgs == 2 => constantFold2(doubleValue, _ - _) + case tpnme.Times if nArgs == 2 => constantFold2(doubleValue, _ * _) + case tpnme.Div if nArgs == 2 => constantFold2(doubleValue, _ / _) + case tpnme.Mod if nArgs == 2 => constantFold2(doubleValue, _ % _) + case tpnme.Lt if nArgs == 2 => constantFold2(doubleValue, _ < _) + case tpnme.Gt if nArgs == 2 => constantFold2(doubleValue, _ > _) + case tpnme.Ge if nArgs == 2 => constantFold2(doubleValue, _ >= _) + case tpnme.Le if nArgs == 2 => constantFold2(doubleValue, _ <= _) + case tpnme.Min if nArgs == 2 => constantFold2(doubleValue, _ min _) + case tpnme.Max if nArgs == 2 => constantFold2(doubleValue, _ max _) + case tpnme.ToInt if nArgs == 1 => constantFold1(doubleValue, _.toInt) + case tpnme.ToLong if nArgs == 1 => constantFold1(doubleValue, _.toLong) + case tpnme.ToFloat if nArgs == 1 => constantFold1(doubleValue, _.toFloat) case _ => None } else if (owner == defn.CompiletimeOpsStringModuleClass) name match { case tpnme.Plus if nArgs == 2 => constantFold2(stringValue, _ + _) + case tpnme.Length if nArgs == 1 => constantFold1(stringValue, _.length) + case tpnme.Matches if nArgs == 2 => constantFold2(stringValue, _ matches _) + case tpnme.Substring if nArgs == 3 => + constantFold3(stringValue, intValue, intValue, (s, b, e) => s.substring(b, e)) case _ => None } else if (owner == defn.CompiletimeOpsBooleanModuleClass) name match { case tpnme.Not if nArgs == 1 => constantFold1(boolValue, x => !x) diff --git a/library/src/scala/compiletime/ops/any.scala b/library/src/scala/compiletime/ops/any.scala index 0cb7e6d06431..0a6ed4c3e3d7 100644 --- a/library/src/scala/compiletime/ops/any.scala +++ b/library/src/scala/compiletime/ops/any.scala @@ -21,3 +21,22 @@ object any: * @syntax markdown */ type !=[X, Y] <: Boolean + + /** Tests if a type is a constant. + * ```scala + * val c1: IsConst[1] = true + * val c2: IsConst["hi"] = true + * val c3: IsConst[false] = true + * ``` + * @syntax markdown + */ + type IsConst[X] <: Boolean + + /** String conversion of a constant singleton type. + * ```scala + * val s1: ToString[1] = "1" + * val sTrue: ToString[true] = "true" + * ``` + * @syntax markdown + */ + type ToString[X] <: String \ No newline at end of file diff --git a/library/src/scala/compiletime/ops/double.scala b/library/src/scala/compiletime/ops/double.scala new file mode 100644 index 000000000000..783b0ac8b287 --- /dev/null +++ b/library/src/scala/compiletime/ops/double.scala @@ -0,0 +1,136 @@ +package scala.compiletime +package ops + +object double: + /** Addition of two `Double` singleton types. + * ```scala + * val sum: 2.0 + 2.0 = 4.0 + * ``` + * @syntax markdown + */ + type +[X <: Double, Y <: Double] <: Double + + /** Subtraction of two `Double` singleton types. + * ```scala + * val sub: 4.0 - 2.0 = 2.0 + * ``` + * @syntax markdown + */ + type -[X <: Double, Y <: Double] <: Double + + /** Multiplication of two `Double` singleton types. + * ```scala + * val mul: 4.0 * 2.0 = 8.0 + * ``` + * @syntax markdown + */ + type *[X <: Double, Y <: Double] <: Double + + /** Integer division of two `Double` singleton types. + * ```scala + * val div: 5.0 / 2.0 = 2.0 + * ``` + * @syntax markdown + */ + type /[X <: Double, Y <: Double] <: Double + + /** Remainder of the division of `X` by `Y`. + * ```scala + * val mod: 5.0 % 2.0 = 1.0 + * ``` + * @syntax markdown + */ + type %[X <: Double, Y <: Double] <: Double + + /** Less-than comparison of two `Double` singleton types. + * ```scala + * val lt1: 4.0 < 2.0 = false + * val lt2: 2.0 < 4.0 = true + * ``` + * @syntax markdown + */ + type <[X <: Double, Y <: Double] <: Boolean + + /** Greater-than comparison of two `Double` singleton types. + * ```scala + * val gt1: 4.0 > 2.0 = true + * val gt2: 2.0 > 2.0 = false + * ``` + * @syntax markdown + */ + type >[X <: Double, Y <: Double] <: Boolean + + /** Greater-or-equal comparison of two `Double` singleton types. + * ```scala + * val ge1: 4.0 >= 2.0 = true + * val ge2: 2.0 >= 3.0 = false + * ``` + * @syntax markdown + */ + type >=[X <: Double, Y <: Double] <: Boolean + + /** Less-or-equal comparison of two `Double` singleton types. + * ```scala + * val lt1: 4.0 <= 2.0 = false + * val lt2: 2.0 <= 2.0 = true + * ``` + * @syntax markdown + */ + type <=[X <: Double, Y <: Double] <: Boolean + + /** Absolute value of an `Double` singleton type. + * ```scala + * val abs: Abs[-1.0] = 1.0 + * ``` + * @syntax markdown + */ + type Abs[X <: Double] <: Double + + /** Negation of an `Double` singleton type. + * ```scala + * val neg1: Neg[-1.0] = 1.0 + * val neg2: Neg[1.0] = -1.0 + * ``` + * @syntax markdown + */ + type Negate[X <: Double] <: Double + + /** Minimum of two `Double` singleton types. + * ```scala + * val min: Min[-1.0, 1.0] = -1.0 + * ``` + * @syntax markdown + */ + type Min[X <: Double, Y <: Double] <: Double + + /** Maximum of two `Double` singleton types. + * ```scala + * val max: Max[-1.0, 1.0] = 1.0 + * ``` + * @syntax markdown + */ + type Max[X <: Double, Y <: Double] <: Double + + /** Int conversion of a `Double` singleton type. + * ```scala + * val x: ToInt[1.0] = 1 + * ``` + * @syntax markdown + */ + type ToInt[X <: Double] <: Int + + /** Long conversion of a `Double` singleton type. + * ```scala + * val x: ToLong[1.0] = 1L + * ``` + * @syntax markdown + */ + type ToLong[X <: Double] <: Long + + /** Float conversion of a `Double` singleton type. + * ```scala + * val x: ToFloat[1.0] = 1.0f + * ``` + * @syntax markdown + */ + type ToFloat[X <: Double] <: Float \ No newline at end of file diff --git a/library/src/scala/compiletime/ops/float.scala b/library/src/scala/compiletime/ops/float.scala new file mode 100644 index 000000000000..7330959f461b --- /dev/null +++ b/library/src/scala/compiletime/ops/float.scala @@ -0,0 +1,136 @@ +package scala.compiletime +package ops + +object float: + /** Addition of two `Float` singleton types. + * ```scala + * val sum: 2.0f + 2.0f = 4.0f + * ``` + * @syntax markdown + */ + type +[X <: Float, Y <: Float] <: Float + + /** Subtraction of two `Float` singleton types. + * ```scala + * val sub: 4.0f - 2.0f = 2.0f + * ``` + * @syntax markdown + */ + type -[X <: Float, Y <: Float] <: Float + + /** Multiplication of two `Float` singleton types. + * ```scala + * val mul: 4.0f * 2.0f = 8.0f + * ``` + * @syntax markdown + */ + type *[X <: Float, Y <: Float] <: Float + + /** Integer division of two `Float` singleton types. + * ```scala + * val div: 5.0f / 2.0f = 2.0f + * ``` + * @syntax markdown + */ + type /[X <: Float, Y <: Float] <: Float + + /** Remainder of the division of `X` by `Y`. + * ```scala + * val mod: 5.0f % 2.0f = 1.0f + * ``` + * @syntax markdown + */ + type %[X <: Float, Y <: Float] <: Float + + /** Less-than comparison of two `Float` singleton types. + * ```scala + * val lt1: 4.0f < 2.0f = false + * val lt2: 2.0f < 4.0f = true + * ``` + * @syntax markdown + */ + type <[X <: Float, Y <: Float] <: Boolean + + /** Greater-than comparison of two `Float` singleton types. + * ```scala + * val gt1: 4.0f > 2.0f = true + * val gt2: 2.0f > 2.0f = false + * ``` + * @syntax markdown + */ + type >[X <: Float, Y <: Float] <: Boolean + + /** Greater-or-equal comparison of two `Float` singleton types. + * ```scala + * val ge1: 4.0f >= 2.0f = true + * val ge2: 2.0f >= 3.0f = false + * ``` + * @syntax markdown + */ + type >=[X <: Float, Y <: Float] <: Boolean + + /** Less-or-equal comparison of two `Float` singleton types. + * ```scala + * val lt1: 4.0f <= 2.0f = false + * val lt2: 2.0f <= 2.0f = true + * ``` + * @syntax markdown + */ + type <=[X <: Float, Y <: Float] <: Boolean + + /** Absolute value of an `Float` singleton type. + * ```scala + * val abs: Abs[-1.0f] = 1.0f + * ``` + * @syntax markdown + */ + type Abs[X <: Float] <: Float + + /** Negation of an `Float` singleton type. + * ```scala + * val neg1: Neg[-1.0f] = 1.0f + * val neg2: Neg[1.0f] = -1.0f + * ``` + * @syntax markdown + */ + type Negate[X <: Float] <: Float + + /** Minimum of two `Float` singleton types. + * ```scala + * val min: Min[-1.0f, 1.0f] = -1.0f + * ``` + * @syntax markdown + */ + type Min[X <: Float, Y <: Float] <: Float + + /** Maximum of two `Float` singleton types. + * ```scala + * val max: Max[-1.0f, 1.0f] = 1.0f + * ``` + * @syntax markdown + */ + type Max[X <: Float, Y <: Float] <: Float + + /** Int conversion of a `Float` singleton type. + * ```scala + * val x: ToInt[1.0f] = 1 + * ``` + * @syntax markdown + */ + type ToInt[X <: Float] <: Int + + /** Long conversion of a `Float` singleton type. + * ```scala + * val x: ToLong[1.0f] = 1L + * ``` + * @syntax markdown + */ + type ToLong[X <: Float] <: Long + + /** Double conversion of a `Float` singleton type. + * ```scala + * val x: ToDouble[1.0f] = 1.0 + * ``` + * @syntax markdown + */ + type ToDouble[X <: Float] <: Double diff --git a/library/src/scala/compiletime/ops/int.scala b/library/src/scala/compiletime/ops/int.scala index 70339eed12e7..890909963b01 100644 --- a/library/src/scala/compiletime/ops/int.scala +++ b/library/src/scala/compiletime/ops/int.scala @@ -181,4 +181,43 @@ object int: * ``` * @syntax markdown */ + @deprecated("Use compiletime.ops.any.ToString instead.","3.1.0") type ToString[X <: Int] <: String + + /** Long conversion of an `Int` singleton type. + * ```scala + * val x: ToLong[1] = 1L + * ``` + * @syntax markdown + */ + type ToLong[X <: Int] <: Long + + /** Float conversion of an `Int` singleton type. + * ```scala + * val x: ToFloat[1] = 1.0f + * ``` + * @syntax markdown + */ + type ToFloat[X <: Int] <: Float + + /** Double conversion of an `Int` singleton type. + * ```scala + * val x: ToDouble[1] = 1.0 + * ``` + * @syntax markdown + */ + type ToDouble[X <: Int] <: Double + + /** Number of zero bits preceding the highest-order ("leftmost") + * one-bit in the two's complement binary representation of the specified `Int` singleton type. + * Returns 32 if the specified singleton type has no one-bits in its two's complement representation, + * in other words if it is equal to zero. + * ```scala + * val zero_lzc: NumberOfLeadingZeros[0] = 32 + * val eight_lzc: NumberOfLeadingZeros[8] = 28 + * type Log2[N <: Int] = 31 - NumberOfLeadingZeros[N] + * val log2of8: Log2[8] = 3 + * ``` + * @syntax markdown + */ + type NumberOfLeadingZeros[X <: Int] <: Int \ No newline at end of file diff --git a/library/src/scala/compiletime/ops/long.scala b/library/src/scala/compiletime/ops/long.scala new file mode 100644 index 000000000000..920d7c81d349 --- /dev/null +++ b/library/src/scala/compiletime/ops/long.scala @@ -0,0 +1,222 @@ +package scala.compiletime +package ops + +object long: + /** Successor of a natural number where zero is the type 0 and successors are reduced as if the definition was + * + * ```scala + * type S[N <: Long] <: Long = N match { + * case 0L => 1L + * case 1L => 2L + * case 2L => 3L + * ... + * case 9223372036854775806L => 9223372036854775807L + * } + * ``` + * @syntax markdown + */ + type S[N <: Long] <: Long + + /** Addition of two `Long` singleton types. + * ```scala + * val sum: 2L + 2L = 4L + * ``` + * @syntax markdown + */ + type +[X <: Long, Y <: Long] <: Long + + /** Subtraction of two `Long` singleton types. + * ```scala + * val sub: 4L - 2L = 2L + * ``` + * @syntax markdown + */ + type -[X <: Long, Y <: Long] <: Long + + /** Multiplication of two `Long` singleton types. + * ```scala + * val mul: 4L * 2L = 8L + * ``` + * @syntax markdown + */ + type *[X <: Long, Y <: Long] <: Long + + /** Integer division of two `Long` singleton types. + * ```scala + * val div: 5L / 2L = 2L + * ``` + * @syntax markdown + */ + type /[X <: Long, Y <: Long] <: Long + + /** Remainder of the division of `X` by `Y`. + * ```scala + * val mod: 5L % 2L = 1L + * ``` + * @syntax markdown + */ + type %[X <: Long, Y <: Long] <: Long + + /** Binary left shift of `X` by `Y`. + * ```scala + * val lshift: 1L << 2L = 4L + * ``` + * @syntax markdown + */ + type <<[X <: Long, Y <: Long] <: Long + + /** Binary right shift of `X` by `Y`. + * ```scala + * val rshift: 10L >> 1L = 5L + * ``` + * @syntax markdown + */ + type >>[X <: Long, Y <: Long] <: Long + + /** Binary right shift of `X` by `Y`, filling the left with zeros. + * ```scala + * val rshiftzero: 10L >>> 1L = 5L + * ``` + * @syntax markdown + */ + type >>>[X <: Long, Y <: Long] <: Long + + /** Bitwise xor of `X` and `Y`. + * ```scala + * val xor: 10L ^ 30L = 20L + * ``` + * @syntax markdown + */ + type ^[X <: Long, Y <: Long] <: Long + + /** Less-than comparison of two `Long` singleton types. + * ```scala + * val lt1: 4L < 2L = false + * val lt2: 2L < 4L = true + * ``` + * @syntax markdown + */ + type <[X <: Long, Y <: Long] <: Boolean + + /** Greater-than comparison of two `Long` singleton types. + * ```scala + * val gt1: 4L > 2L = true + * val gt2: 2L > 2L = false + * ``` + * @syntax markdown + */ + type >[X <: Long, Y <: Long] <: Boolean + + /** Greater-or-equal comparison of two `Long` singleton types. + * ```scala + * val ge1: 4L >= 2L = true + * val ge2: 2L >= 3L = false + * ``` + * @syntax markdown + */ + type >=[X <: Long, Y <: Long] <: Boolean + + /** Less-or-equal comparison of two `Long` singleton types. + * ```scala + * val lt1: 4L <= 2L = false + * val lt2: 2L <= 2L = true + * ``` + * @syntax markdown + */ + type <=[X <: Long, Y <: Long] <: Boolean + + /** Bitwise and of `X` and `Y`. + * ```scala + * val and1: BitwiseAnd[4L, 4L] = 4L + * val and2: BitwiseAnd[10L, 5L] = 0L + * ``` + * @syntax markdown + */ + type BitwiseAnd[X <: Long, Y <: Long] <: Long + + /** Bitwise or of `X` and `Y`. + * ```scala + * val or: BitwiseOr[10L, 11L] = 11L + * ``` + * @syntax markdown + */ + type BitwiseOr[X <: Long, Y <: Long] <: Long + + /** Absolute value of an `Long` singleton type. + * ```scala + * val abs: Abs[-1L] = 1L + * ``` + * @syntax markdown + */ + type Abs[X <: Long] <: Long + + /** Negation of an `Long` singleton type. + * ```scala + * val neg1: Neg[-1L] = 1L + * val neg2: Neg[1L] = -1L + * ``` + * @syntax markdown + */ + type Negate[X <: Long] <: Long + + /** Minimum of two `Long` singleton types. + * ```scala + * val min: Min[-1L, 1L] = -1L + * ``` + * @syntax markdown + */ + type Min[X <: Long, Y <: Long] <: Long + + /** Maximum of two `Long` singleton types. + * ```scala + * val max: Max[-1L, 1L] = 1L + * ``` + * @syntax markdown + */ + type Max[X <: Long, Y <: Long] <: Long + + /** String conversion of an `Long` singleton type. + * ```scala + * val abs: ToString[1L] = "1" + * ``` + * @syntax markdown + */ + type ToString[X <: Long] <: String + + /** Number of zero bits preceding the highest-order ("leftmost") + * one-bit in the two's complement binary representation of the specified `Long` singleton type. + * Returns 64 if the specified singleton type has no one-bits in its two's complement representation, + * in other words if it is equal to zero. + * ```scala + * val zero_lzc: NumberOfLeadingZeros[0L] = 64 + * val eight_lzc: NumberOfLeadingZeros[8L] = 60 + * type Log2[N <: Long] = int.-[63, NumberOfLeadingZeros[N]] + * val log2of8: Log2[8L] = 3 + * ``` + * @syntax markdown + */ + type NumberOfLeadingZeros[X <: Long] <: Int + + /** Int conversion of a `Long` singleton type. + * ```scala + * val x: ToInt[1L] = 1 + * ``` + * @syntax markdown + */ + type ToInt[X <: Long] <: Int + + /** Float conversion of a `Long` singleton type. + * ```scala + * val x: ToFloat[1L] = 1.0f + * ``` + * @syntax markdown + */ + type ToFloat[X <: Long] <: Float + + /** Double conversion of a `Long` singleton type. + * ```scala + * val x: ToDouble[1L] = 1.0 + * ``` + * @syntax markdown + */ + type ToDouble[X <: Long] <: Double diff --git a/library/src/scala/compiletime/ops/string.scala b/library/src/scala/compiletime/ops/string.scala index 0969ceb60053..d30f03b904c0 100644 --- a/library/src/scala/compiletime/ops/string.scala +++ b/library/src/scala/compiletime/ops/string.scala @@ -9,3 +9,32 @@ object string: * @syntax markdown */ type +[X <: String, Y <: String] <: String + + /** Length of a `String` singleton type. + * ```scala + * val helloSize: Size["hello"] = 5 + * ``` + * @syntax markdown + */ + type Length[X <: String] <: Int + + /** Substring of a `String` singleton type, with a singleton type + * begin inclusive index `IBeg`, and a singleton type exclusive end index `IEnd`. + * The substring begins at the specified IBeg and extends to the character at index IEnd - 1. + * Thus the length of the substring is IEnd-IBeg. + * ```scala + * val x: Substring["hamburger", 4, 8] = "urge" + * val y: Substring["smiles", 1, 5] = "mile" + * ``` + * @syntax markdown + */ + type Substring[S <: String, IBeg <: Int, IEnd <: Int] <: String + + /** Tests if this `String` singleton type matches the given + * regular expression `String` singleton type. + * ```scala + * val x: Matches["unhappy", "un.*"] = true + * ``` + * @syntax markdown + */ + type Matches[S <: String, Regex <: String] <: Boolean diff --git a/tests/neg/singleton-ops-any.check b/tests/neg/singleton-ops-any.check index 6de768fa0b2e..be234d405b4e 100644 --- a/tests/neg/singleton-ops-any.check +++ b/tests/neg/singleton-ops-any.check @@ -26,3 +26,17 @@ longer explanation available when compiling with `-explain` | Required: (false : Boolean) longer explanation available when compiling with `-explain` +-- [E007] Type Mismatch Error: tests/neg/singleton-ops-any.scala:18:27 ------------------------------------------------- +18 | val t04: ToString[Int] = "Int" // error + | ^^^^^ + | Found: ("Int" : String) + | Required: compiletime.ops.any.ToString[Int] + +longer explanation available when compiling with `-explain` +-- [E007] Type Mismatch Error: tests/neg/singleton-ops-any.scala:32:26 ------------------------------------------------- +32 | val t48: IsConst[Any] = true // error + | ^^^^ + | Found: (true : Boolean) + | Required: (false : Boolean) + +longer explanation available when compiling with `-explain` diff --git a/tests/neg/singleton-ops-any.scala b/tests/neg/singleton-ops-any.scala index 0d7c05b55fec..33951f58bcd9 100644 --- a/tests/neg/singleton-ops-any.scala +++ b/tests/neg/singleton-ops-any.scala @@ -11,4 +11,24 @@ object Test { val t37: 0 != 1 = true val t38: false != 5 = false // error val t39: 10 != 10 = true // error + + val t01: ToString[1] = "1" + val t02: ToString[-2L] = "-2" + val t03: ToString[true] = "true" + val t04: ToString[Int] = "Int" // error + val t05: ToString[3.33] = "3.33" + val t06: ToString["123"] = "123" + + val t40: IsConst[1] = true + val t41: IsConst[2L] = true + val t42: IsConst[-1.0] = true + val t43: IsConst[false] = true + val t44: IsConst["hi"] = true + val t45: IsConst[Int] = false + val one : Int = 1 + val t46 : IsConst[one.type] = false + final val two = 2 + val t47 : IsConst[two.type] = true + val t48: IsConst[Any] = true // error + } diff --git a/tests/neg/singleton-ops-double.scala b/tests/neg/singleton-ops-double.scala new file mode 100644 index 000000000000..006b86270657 --- /dev/null +++ b/tests/neg/singleton-ops-double.scala @@ -0,0 +1,77 @@ +import scala.compiletime.ops.double.* + +object Test { + summon[2.0 + 3.0 =:= 6.0 - 1.0] + summon[1763.0 =:= 41.0 * 43.0] + summon[2.0 + 2.0 =:= 3.0] // error + summon[29.0 * 31.0 =:= 900.0] // error + summon[Double <:< Double + 1.0] // error + summon[1.0 + Double <:< Double] + + val t0: 2.0 + 3.0 = 5.0 + val t1: 2.0 + 2.0 = 5.0 // error + val t2: -1.0 + 1.0 = 0.0 + val t3: -5.0 + -5.0 = -11.0 // error + + val t4: 10.0 * 20.0 = 200.0 + val t5: 30.0 * 10.0 = 400.0 // error + val t6: -10.0 * 2.0 = -20.0 + val t7: -2.0 * -2.0 = 4.0 + + val t8: 10.0 / 2.0 = 5.0 + val t9: 11.0 / -2.0 = -5.5 + val t10: 2.0 / 4.0 = 2.0 // error + + val t12: 10.0 % 3.0 = 1.0 + val t13: 12.0 % 2.0 = 1.0 // error + val t14: 1.0 % -3.0 = 1.0 + + val t16: 1.0 < 0.0 = false + val t17: 0.0 < 1.0 = true + val t18: 10.0 < 5.0 = true // error + val t19: 5.0 < 10.0 = false // error + + val t20: 1.0 <= 0.0 = false + val t21: 1.0 <= 1.0 = true + val t22: 10.0 <= 5.0 = true // error + val t23: 5.0 <= 10.0 = false // error + + val t24: 1.0 > 0.0 = true + val t25: 0.0 > 1.0 = false + val t26: 10.0 > 5.0 = false // error + val t27: 5.0 > 10.0 = true // error + + val t28: 1.0 >= 1.0 = true + val t29: 0.0 >= 1.0 = false + val t30: 10.0 >= 5.0 = false // error + val t31: 5.0 >= 10.0 = true // error + + val t32: Abs[0.0] = 0.0 + val t33: Abs[-1.0] = 1.0 + val t34: Abs[-1.0] = -1.0 // error + val t35: Abs[1.0] = -1.0 // error + + val t36: Negate[-10.0] = 10.0 + val t37: Negate[10.0] = -10.0 + val t38: Negate[1.0] = 1.0 // error + val t39: Negate[-1.0] = -1.0 // error + + val t40: Max[-1.0, 10.0] = 10.0 + val t41: Max[4.0, 2.0] = 4.0 + val t42: Max[2.0, 2.0] = 1.0 // error + val t43: Max[-1.0, -1.0] = 0.0 // error + + val t44: Min[-1.0, 10.0] = -1.0 + val t45: Min[4.0, 2.0] = 2.0 + val t46: Min[2.0, 2.0] = 1.0 // error + val t47: Min[-1.0, -1.0] = 0.0 // error + + val t79: ToInt[1.0] = 1 + val t80: ToInt[3.0] = 2 // error + + val t81: ToLong[1.0] = 1L + val t82: ToLong[2.0] = 2 // error + + val t83: ToFloat[1.0] = 1.0f + val t84: ToFloat[2.0] = 2 // error +} diff --git a/tests/neg/singleton-ops-float.scala b/tests/neg/singleton-ops-float.scala new file mode 100644 index 000000000000..f7263fc804a6 --- /dev/null +++ b/tests/neg/singleton-ops-float.scala @@ -0,0 +1,77 @@ +import scala.compiletime.ops.float.* + +object Test { + summon[2.0f + 3.0f =:= 6.0f - 1.0f] + summon[1763.0f =:= 41.0f * 43.0f] + summon[2.0f + 2.0f =:= 3.0f] // error + summon[29.0f * 31.0f =:= 900.0f] // error + summon[Float <:< Float + 1.0f] // error + summon[1.0f + Float <:< Float] + + val t0: 2.0f + 3.0f = 5.0f + val t1: 2.0f + 2.0f = 5.0f // error + val t2: -1.0f + 1.0f = 0.0f + val t3: -5.0f + -5.0f = -11.0f // error + + val t4: 10.0f * 20.0f = 200.0f + val t5: 30.0f * 10.0f = 400.0f // error + val t6: -10.0f * 2.0f = -20.0f + val t7: -2.0f * -2.0f = 4.0f + + val t8: 10.0f / 2.0f = 5.0f + val t9: 11.0f / -2.0f = -5.5f + val t10: 2.0f / 4.0f = 2.0f // error + + val t12: 10.0f % 3.0f = 1.0f + val t13: 12.0f % 2.0f = 1.0f // error + val t14: 1.0f % -3.0f = 1.0f + + val t16: 1.0f < 0.0f = false + val t17: 0.0f < 1.0f = true + val t18: 10.0f < 5.0f = true // error + val t19: 5.0f < 10.0f = false // error + + val t20: 1.0f <= 0.0f = false + val t21: 1.0f <= 1.0f = true + val t22: 10.0f <= 5.0f = true // error + val t23: 5.0f <= 10.0f = false // error + + val t24: 1.0f > 0.0f = true + val t25: 0.0f > 1.0f = false + val t26: 10.0f > 5.0f = false // error + val t27: 5.0f > 10.0f = true // error + + val t28: 1.0f >= 1.0f = true + val t29: 0.0f >= 1.0f = false + val t30: 10.0f >= 5.0f = false // error + val t31: 5.0f >= 10.0f = true // error + + val t32: Abs[0.0f] = 0.0f + val t33: Abs[-1.0f] = 1.0f + val t34: Abs[-1.0f] = -1.0f // error + val t35: Abs[1.0f] = -1.0f // error + + val t36: Negate[-10.0f] = 10.0f + val t37: Negate[10.0f] = -10.0f + val t38: Negate[1.0f] = 1.0f // error + val t39: Negate[-1.0f] = -1.0f // error + + val t40: Max[-1.0f, 10.0f] = 10.0f + val t41: Max[4.0f, 2.0f] = 4.0f + val t42: Max[2.0f, 2.0f] = 1.0f // error + val t43: Max[-1.0f, -1.0f] = 0.0f // error + + val t44: Min[-1.0f, 10.0f] = -1.0f + val t45: Min[4.0f, 2.0f] = 2.0f + val t46: Min[2.0f, 2.0f] = 1.0f // error + val t47: Min[-1.0f, -1.0f] = 0.0f // error + + val t79: ToInt[1.0f] = 1 + val t80: ToInt[3.0f] = 2 // error + + val t81: ToLong[1.0f] = 1L + val t82: ToLong[2.0f] = 2 // error + + val t83: ToDouble[1.0f] = 1.0 + val t84: ToDouble[2.0f] = 2 // error +} diff --git a/tests/neg/singleton-ops-int.scala b/tests/neg/singleton-ops-int.scala index d2fd3a73afcd..ca2d3d6ea107 100644 --- a/tests/neg/singleton-ops-int.scala +++ b/tests/neg/singleton-ops-int.scala @@ -9,6 +9,9 @@ object Test { summon[1 + Int <:< Int] val t0: 2 + 3 = 5 + final val two = 2 + final val three = 3 + val t0_b : two.type + three.type = 5 val t1: 2 + 2 = 5 // error val t2: -1 + 1 = 0 val t3: -5 + -5 = -11 // error @@ -68,10 +71,8 @@ object Test { val t46: Min[2, 2] = 1 // error val t47: Min[-1, -1] = 0 // error - val t48: ToString[213] = "213" - val t49: ToString[-1] = "-1" - val t50: ToString[0] = "-0" // error - val t51: ToString[200] = "100" // error + val t48: ToString[213] = "213" // warning (deprecation) + val t49: ToString[-1] = "-1" // warning (deprecation) val t52: 1 ^ 2 = 3 val t53: 1 ^ 3 = 3 // error @@ -102,4 +103,17 @@ object Test { val t73: -7 >>> 3 = 536870911 val t74: -7 >>> 3 = -1 // error + val t75: NumberOfLeadingZeros[0] = 32 + val t76: NumberOfLeadingZeros[8] = 28 + val t77: NumberOfLeadingZeros[-1] = 0 + val t78: NumberOfLeadingZeros[-1] = 1 // error + + val t79: ToLong[1] = 1L + val t80: ToLong[2] = 2 // error + + val t81: ToFloat[1] = 1.0f + val t82: ToFloat[2] = 2 // error + + val t83: ToDouble[1] = 1.0 + val t84: ToDouble[2] = 2 // error } diff --git a/tests/neg/singleton-ops-long.scala b/tests/neg/singleton-ops-long.scala new file mode 100644 index 000000000000..5af2069beb27 --- /dev/null +++ b/tests/neg/singleton-ops-long.scala @@ -0,0 +1,113 @@ +import scala.compiletime.ops.long.* + +object Test { + summon[2L + 3L =:= 6L - 1L] + summon[1763L =:= 41L * 43L] + summon[2L + 2L =:= 3L] // error + summon[29L * 31L =:= 900L] // error + summon[Long <:< Long + 1L] // error + summon[1L + Long <:< Long] + + val t0: 2L + 3L = 5L + val t1: 2L + 2L = 5L // error + val t2: -1L + 1L = 0L + val t3: -5L + -5L = -11L // error + + val t4: 10L * 20L = 200L + val t5: 30L * 10L = 400L // error + val t6: -10L * 2L = -20L + val t7: -2L * -2L = 4L + + val t8: 10L / 2L = 5L + val t9: 11L / -2L = -5L // Integer division + val t10: 2L / 4L = 2L // error + val t11: -1L / 0L = 1L // error + + val t12: 10L % 3L = 1L + val t13: 12L % 2L = 1L // error + val t14: 1L % -3L = 1L + val t15: -3L % 0L = 0L // error + + val t16: 1L < 0L = false + val t17: 0L < 1L = true + val t18: 10L < 5L = true // error + val t19: 5L < 10L = false // error + + val t20: 1L <= 0L = false + val t21: 1L <= 1L = true + val t22: 10L <= 5L = true // error + val t23: 5L <= 10L = false // error + + val t24: 1L > 0L = true + val t25: 0L > 1L = false + val t26: 10L > 5L = false // error + val t27: 5L > 10L = true // error + + val t28: 1L >= 1L = true + val t29: 0L >= 1L = false + val t30: 10L >= 5L = false // error + val t31: 5L >= 10L = true // error + + val t32: Abs[0L] = 0L + val t33: Abs[-1L] = 1L + val t34: Abs[-1L] = -1L // error + val t35: Abs[1L] = -1L // error + + val t36: Negate[-10L] = 10L + val t37: Negate[10L] = -10L + val t38: Negate[1L] = 1L // error + val t39: Negate[-1L] = -1L // error + + val t40: Max[-1L, 10L] = 10L + val t41: Max[4L, 2L] = 4L + val t42: Max[2L, 2L] = 1L // error + val t43: Max[-1L, -1L] = 0L // error + + val t44: Min[-1L, 10L] = -1L + val t45: Min[4L, 2L] = 2L + val t46: Min[2L, 2L] = 1L // error + val t47: Min[-1L, -1L] = 0L // error + + val t52: 1L ^ 2L = 3L + val t53: 1L ^ 3L = 3L // error + val t54: -1L ^ -2L = 1L + val t55: -1L ^ -3L = 1L // error + + val t56: BitwiseOr[1L, 2L] = 3L + val t57: BitwiseOr[10L, 12L] = 13L // error + val t58: BitwiseOr[-11L, 12L] = -3L + val t59: BitwiseOr[-111L, -10L] = 0L // error + + val t60: BitwiseAnd[1L, 1L] = 1L + val t61: BitwiseAnd[1L, 2L] = 0L + val t62: BitwiseAnd[-1L, -3L] = 3L // error + val t63: BitwiseAnd[-1L, -1L] = 1L // error + + val t64: 1L << 1L = 2L + val t65: 1L << 2L = 4L + val t66: 1L << 3L = 8L + val t67: 1L << 4L = 0L // error + + val t68: 100L >> 2L = 25L + val t69: 123456789L >> 71L = 964506L + val t70: -7L >> 3L = -1L + val t71: -7L >> 3L = 0L // error + + val t72: -1L >>> 10000L = 281474976710655L + val t73: -7L >>> 3L = 2305843009213693951L + val t74: -7L >>> 3L = -1L // error + + val t75: NumberOfLeadingZeros[0L] = 64 + val t76: NumberOfLeadingZeros[8L] = 60 + val t77: NumberOfLeadingZeros[-1L] = 0 + val t78: NumberOfLeadingZeros[-1L] = 1 // error + + val t79: ToInt[1L] = 1 + val t80: ToInt[3L] = 2 // error + + val t81: ToFloat[1L] = 1.0f + val t82: ToFloat[2L] = 2 // error + + val t83: ToDouble[1L] = 1.0 + val t84: ToDouble[2L] = 2 // error +} diff --git a/tests/neg/singleton-ops-string.scala b/tests/neg/singleton-ops-string.scala index 46093121d3c4..d9cf2377564b 100644 --- a/tests/neg/singleton-ops-string.scala +++ b/tests/neg/singleton-ops-string.scala @@ -5,4 +5,14 @@ object Test { val t1: "" + "" = "" val t2: "3" + "" = "33" // error val t3: "Hello " + "world" = "error" // error + + val t4: Length["Hello"] = 5 + val t5: Length[""] = 0 + val t6: Length["1"] = 7 // error + + val t7: Substring["hamburger", 4, 8] = "urge" + val t8: Substring["hamburger", 4, 8] = "urger" // error + + val t9: Matches["hamburger", "ham.*"] = true + val t10: Matches["hamburger", "ham.*"] = false // error } From 68483141e0931a8e4cfb07168c74ceb2a2f69271 Mon Sep 17 00:00:00 2001 From: oronpo Date: Mon, 25 Oct 2021 18:31:15 -0400 Subject: [PATCH 0850/1244] add experimental annotation to added type operations and update MiMa Update MiMaFilters.scala Update MiMaFilters.scala --- library/src/scala/compiletime/ops/any.scala | 4 +++ .../src/scala/compiletime/ops/double.scala | 3 ++ library/src/scala/compiletime/ops/float.scala | 3 ++ library/src/scala/compiletime/ops/int.scala | 6 ++++ library/src/scala/compiletime/ops/long.scala | 3 ++ .../src/scala/compiletime/ops/string.scala | 5 +++ project/MiMaFilters.scala | 31 ++++++++++++++----- 7 files changed, 47 insertions(+), 8 deletions(-) diff --git a/library/src/scala/compiletime/ops/any.scala b/library/src/scala/compiletime/ops/any.scala index 0a6ed4c3e3d7..60b86414a385 100644 --- a/library/src/scala/compiletime/ops/any.scala +++ b/library/src/scala/compiletime/ops/any.scala @@ -1,6 +1,8 @@ package scala.compiletime package ops +import annotation.experimental + object any: /** Equality comparison of two singleton types. * ```scala @@ -30,6 +32,7 @@ object any: * ``` * @syntax markdown */ + @experimental type IsConst[X] <: Boolean /** String conversion of a constant singleton type. @@ -39,4 +42,5 @@ object any: * ``` * @syntax markdown */ + @experimental type ToString[X] <: String \ No newline at end of file diff --git a/library/src/scala/compiletime/ops/double.scala b/library/src/scala/compiletime/ops/double.scala index 783b0ac8b287..e06ff64c3f05 100644 --- a/library/src/scala/compiletime/ops/double.scala +++ b/library/src/scala/compiletime/ops/double.scala @@ -1,6 +1,9 @@ package scala.compiletime package ops +import scala.annotation.experimental + +@experimental object double: /** Addition of two `Double` singleton types. * ```scala diff --git a/library/src/scala/compiletime/ops/float.scala b/library/src/scala/compiletime/ops/float.scala index 7330959f461b..d5aeb2d5f4f7 100644 --- a/library/src/scala/compiletime/ops/float.scala +++ b/library/src/scala/compiletime/ops/float.scala @@ -1,6 +1,9 @@ package scala.compiletime package ops +import scala.annotation.experimental + +@experimental object float: /** Addition of two `Float` singleton types. * ```scala diff --git a/library/src/scala/compiletime/ops/int.scala b/library/src/scala/compiletime/ops/int.scala index 890909963b01..090e3312421f 100644 --- a/library/src/scala/compiletime/ops/int.scala +++ b/library/src/scala/compiletime/ops/int.scala @@ -1,6 +1,8 @@ package scala.compiletime package ops +import annotation.experimental + object int: /** Successor of a natural number where zero is the type 0 and successors are reduced as if the definition was * @@ -190,6 +192,7 @@ object int: * ``` * @syntax markdown */ + @experimental type ToLong[X <: Int] <: Long /** Float conversion of an `Int` singleton type. @@ -198,6 +201,7 @@ object int: * ``` * @syntax markdown */ + @experimental type ToFloat[X <: Int] <: Float /** Double conversion of an `Int` singleton type. @@ -206,6 +210,7 @@ object int: * ``` * @syntax markdown */ + @experimental type ToDouble[X <: Int] <: Double /** Number of zero bits preceding the highest-order ("leftmost") @@ -220,4 +225,5 @@ object int: * ``` * @syntax markdown */ + @experimental type NumberOfLeadingZeros[X <: Int] <: Int \ No newline at end of file diff --git a/library/src/scala/compiletime/ops/long.scala b/library/src/scala/compiletime/ops/long.scala index 920d7c81d349..f3158e12c2f6 100644 --- a/library/src/scala/compiletime/ops/long.scala +++ b/library/src/scala/compiletime/ops/long.scala @@ -1,6 +1,9 @@ package scala.compiletime package ops +import scala.annotation.experimental + +@experimental object long: /** Successor of a natural number where zero is the type 0 and successors are reduced as if the definition was * diff --git a/library/src/scala/compiletime/ops/string.scala b/library/src/scala/compiletime/ops/string.scala index d30f03b904c0..51e336ab7adc 100644 --- a/library/src/scala/compiletime/ops/string.scala +++ b/library/src/scala/compiletime/ops/string.scala @@ -1,6 +1,8 @@ package scala.compiletime package ops +import scala.annotation.experimental + object string: /** Concatenation of two `String` singleton types. * ```scala @@ -16,6 +18,7 @@ object string: * ``` * @syntax markdown */ + @experimental type Length[X <: String] <: Int /** Substring of a `String` singleton type, with a singleton type @@ -28,6 +31,7 @@ object string: * ``` * @syntax markdown */ + @experimental type Substring[S <: String, IBeg <: Int, IEnd <: Int] <: String /** Tests if this `String` singleton type matches the given @@ -37,4 +41,5 @@ object string: * ``` * @syntax markdown */ + @experimental type Matches[S <: String, Regex <: String] <: Boolean diff --git a/project/MiMaFilters.scala b/project/MiMaFilters.scala index ae3673016db1..53a23fb8c3f2 100644 --- a/project/MiMaFilters.scala +++ b/project/MiMaFilters.scala @@ -9,13 +9,28 @@ object MiMaFilters { ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.append"), ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#TypeReprMethods.substituteTypes"), ProblemFilters.exclude[DirectMissingMethodProblem]("scala.quoted.Quotes#reflectModule#TypeReprMethods.substituteTypes"), - - // Should have been added in 3.1.0 - // These are only allowed on imports and therefore should not be present in binaries emitted before - // this addition of these members and therefore should not cause any conflicts. - ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.stdLibPatches.language.3.1-migration"), - ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.stdLibPatches.language.3.1"), - ProblemFilters.exclude[MissingClassProblem]("scala.runtime.stdLibPatches.language$3$u002E1$"), - ProblemFilters.exclude[MissingClassProblem]("scala.runtime.stdLibPatches.language$3$u002E1$minusmigration$"), + ProblemFilters.exclude[MissingClassProblem]("scala.compiletime.ops.double"), + ProblemFilters.exclude[MissingClassProblem]("scala.compiletime.ops.double$"), + ProblemFilters.exclude[MissingClassProblem]("scala.compiletime.ops.float"), + ProblemFilters.exclude[MissingClassProblem]("scala.compiletime.ops.float$"), + ProblemFilters.exclude[MissingClassProblem]("scala.compiletime.ops.long"), + ProblemFilters.exclude[MissingClassProblem]("scala.compiletime.ops.long$"), + // LazyVals + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.LazyVals.getStaticOffset"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.LazyVals.getStaticOffset"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.LazyVals.objCAS"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.LazyVals.objCAS"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.LazyVals#Names.evaluating"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.LazyVals#Names.getStaticOffset"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.LazyVals#Names.nullValued"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.LazyVals#Names.objCas"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.LazyVals#Names.waiting"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.LazyVals#Names.waitingAwaitRelease"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.LazyVals#Names.waitingRelease"), + ProblemFilters.exclude[MissingClassProblem]("scala.runtime.LazyVals$Evaluating$"), + ProblemFilters.exclude[MissingClassProblem]("scala.runtime.LazyVals$NULL$"), + ProblemFilters.exclude[MissingClassProblem]("scala.runtime.LazyVals$Waiting"), + ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.LazyVals.Evaluating"), + ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.LazyVals.NULL"), ) } From 1350d815f2f67a842e508a5e09ac5d05488b242d Mon Sep 17 00:00:00 2001 From: oronpo Date: Mon, 25 Oct 2021 18:35:36 -0400 Subject: [PATCH 0851/1244] Deprecation of `int.ToString` will only start from 3.2.0 --- library/src/scala/compiletime/ops/int.scala | 2 +- tests/neg/singleton-ops-int.scala | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/src/scala/compiletime/ops/int.scala b/library/src/scala/compiletime/ops/int.scala index 090e3312421f..8d62b98a27e4 100644 --- a/library/src/scala/compiletime/ops/int.scala +++ b/library/src/scala/compiletime/ops/int.scala @@ -183,7 +183,7 @@ object int: * ``` * @syntax markdown */ - @deprecated("Use compiletime.ops.any.ToString instead.","3.1.0") + @deprecated("Use compiletime.ops.any.ToString instead.","3.2.0") type ToString[X <: Int] <: String /** Long conversion of an `Int` singleton type. diff --git a/tests/neg/singleton-ops-int.scala b/tests/neg/singleton-ops-int.scala index ca2d3d6ea107..e85b6204d1fa 100644 --- a/tests/neg/singleton-ops-int.scala +++ b/tests/neg/singleton-ops-int.scala @@ -71,8 +71,8 @@ object Test { val t46: Min[2, 2] = 1 // error val t47: Min[-1, -1] = 0 // error - val t48: ToString[213] = "213" // warning (deprecation) - val t49: ToString[-1] = "-1" // warning (deprecation) + val t48: ToString[213] = "213" + val t49: ToString[-1] = "-1" val t52: 1 ^ 2 = 3 val t53: 1 ^ 3 = 3 // error From 1cf7a67e564e7e385ba3c0313d642761d2b99517 Mon Sep 17 00:00:00 2001 From: oronpo Date: Mon, 25 Oct 2021 19:31:49 -0400 Subject: [PATCH 0852/1244] Address review comments. Main changes: * Apply common protection against wrong number of arguments. * Exception in an operation is converted into a type error. --- .../src/dotty/tools/dotc/core/Types.scala | 240 +++++++++--------- 1 file changed, 126 insertions(+), 114 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index bb48f9c6ebc0..aa68f4cacad1 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -4208,6 +4208,11 @@ object Types { case tycon: TypeRef if defn.isCompiletimeAppliedType(tycon.symbol) => extension (tp : Type) def fixForEvaluation : Type = tp.normalized.dealias match { + //enable operations for constant singleton terms. E.g.: + //``` + //final val one = 1 + //type Two = one.type + one.type + //``` case tp : TermRef => tp.underlying case tp => tp } @@ -4246,23 +4251,43 @@ object Types { case ConstantType(Constant(n: String)) => Some(n) case _ => None } - def isConst : Option[Type] = args.head.fixForEvaluation match { + + def isConst(tp : Type) : Option[Type] = tp.fixForEvaluation match { case ConstantType(_) => Some(ConstantType(Constant(true))) case _ => Some(ConstantType(Constant(false))) } + + def expectArgsNum(expectedNum : Int) : Unit = + //We can use assert instead of a compiler type error because this error should not + //occur since the type signature of the operation enforces the proper number of args. + assert(args.length == expectedNum, s"Type operation expects $expectedNum arguments but found ${args.length}") + def natValue(tp: Type): Option[Int] = intValue(tp).filter(n => n >= 0 && n < Int.MaxValue) + //Runs the op and returns the result as a constant type. + //If the op throws an exception, then this exception is converted into a type error. + def runConstantOp(op : => Any): Type = + val result = try { + op + } catch { + case e : Throwable => + throw new TypeError(e.getMessage) + } + ConstantType(Constant(result)) + def constantFold1[T](extractor: Type => Option[T], op: T => Any): Option[Type] = - extractor(args.head).map(a => ConstantType(Constant(op(a)))) + expectArgsNum(1) + extractor(args.head).map(a => runConstantOp(op(a))) def constantFold2[T](extractor: Type => Option[T], op: (T, T) => Any): Option[Type] = constantFold2AB(extractor, extractor, op) def constantFold2AB[TA, TB](extractorA: Type => Option[TA], extractorB: Type => Option[TB], op: (TA, TB) => Any): Option[Type] = + expectArgsNum(2) for { - a <- extractorA(args.head) - b <- extractorB(args.last) - } yield ConstantType(Constant(op(a, b))) + a <- extractorA(args(0)) + b <- extractorB(args(1)) + } yield runConstantOp(op(a, b)) def constantFold3[TA, TB, TC]( extractorA: Type => Option[TA], @@ -4270,139 +4295,126 @@ object Types { extractorC: Type => Option[TC], op: (TA, TB, TC) => Any ): Option[Type] = + expectArgsNum(3) for { - a <- extractorA(args.head) + a <- extractorA(args(0)) b <- extractorB(args(1)) - c <- extractorC(args.last) - } yield ConstantType(Constant(op(a, b, c))) + c <- extractorC(args(2)) + } yield runConstantOp(op(a, b, c)) trace(i"compiletime constant fold $this", typr, show = true) { val name = tycon.symbol.name val owner = tycon.symbol.owner - val nArgs = args.length val constantType = if (defn.isCompiletime_S(tycon.symbol)) { - if (nArgs == 1) constantFold1(natValue, _ + 1) - else None + constantFold1(natValue, _ + 1) } else if (owner == defn.CompiletimeOpsAnyModuleClass) name match { - case tpnme.Equals if nArgs == 2 => constantFold2(constValue, _ == _) - case tpnme.NotEquals if nArgs == 2 => constantFold2(constValue, _ != _) - case tpnme.ToString if nArgs == 1 => constantFold1(constValue, _.toString) - case tpnme.IsConst if nArgs == 1 => isConst + case tpnme.Equals => constantFold2(constValue, _ == _) + case tpnme.NotEquals => constantFold2(constValue, _ != _) + case tpnme.ToString => constantFold1(constValue, _.toString) + case tpnme.IsConst => isConst(args.head) case _ => None } else if (owner == defn.CompiletimeOpsIntModuleClass) name match { - case tpnme.Abs if nArgs == 1 => constantFold1(intValue, _.abs) - case tpnme.Negate if nArgs == 1 => constantFold1(intValue, x => -x) + case tpnme.Abs => constantFold1(intValue, _.abs) + case tpnme.Negate => constantFold1(intValue, x => -x) //ToString is deprecated for ops.int, and moved to ops.any - case tpnme.ToString if nArgs == 1 => constantFold1(intValue, _.toString) - case tpnme.Plus if nArgs == 2 => constantFold2(intValue, _ + _) - case tpnme.Minus if nArgs == 2 => constantFold2(intValue, _ - _) - case tpnme.Times if nArgs == 2 => constantFold2(intValue, _ * _) - case tpnme.Div if nArgs == 2 => constantFold2(intValue, { - case (_, 0) => throw new TypeError("Division by 0") - case (a, b) => a / b - }) - case tpnme.Mod if nArgs == 2 => constantFold2(intValue, { - case (_, 0) => throw new TypeError("Modulo by 0") - case (a, b) => a % b - }) - case tpnme.Lt if nArgs == 2 => constantFold2(intValue, _ < _) - case tpnme.Gt if nArgs == 2 => constantFold2(intValue, _ > _) - case tpnme.Ge if nArgs == 2 => constantFold2(intValue, _ >= _) - case tpnme.Le if nArgs == 2 => constantFold2(intValue, _ <= _) - case tpnme.Xor if nArgs == 2 => constantFold2(intValue, _ ^ _) - case tpnme.BitwiseAnd if nArgs == 2 => constantFold2(intValue, _ & _) - case tpnme.BitwiseOr if nArgs == 2 => constantFold2(intValue, _ | _) - case tpnme.ASR if nArgs == 2 => constantFold2(intValue, _ >> _) - case tpnme.LSL if nArgs == 2 => constantFold2(intValue, _ << _) - case tpnme.LSR if nArgs == 2 => constantFold2(intValue, _ >>> _) - case tpnme.Min if nArgs == 2 => constantFold2(intValue, _ min _) - case tpnme.Max if nArgs == 2 => constantFold2(intValue, _ max _) - case tpnme.NumberOfLeadingZeros if nArgs == 1 => constantFold1(intValue, Integer.numberOfLeadingZeros(_)) - case tpnme.ToLong if nArgs == 1 => constantFold1(intValue, _.toLong) - case tpnme.ToFloat if nArgs == 1 => constantFold1(intValue, _.toFloat) - case tpnme.ToDouble if nArgs == 1 => constantFold1(intValue, _.toDouble) + case tpnme.ToString => constantFold1(intValue, _.toString) + case tpnme.Plus => constantFold2(intValue, _ + _) + case tpnme.Minus => constantFold2(intValue, _ - _) + case tpnme.Times => constantFold2(intValue, _ * _) + case tpnme.Div => constantFold2(intValue, _ / _) + case tpnme.Mod => constantFold2(intValue, _ % _) + case tpnme.Lt => constantFold2(intValue, _ < _) + case tpnme.Gt => constantFold2(intValue, _ > _) + case tpnme.Ge => constantFold2(intValue, _ >= _) + case tpnme.Le => constantFold2(intValue, _ <= _) + case tpnme.Xor => constantFold2(intValue, _ ^ _) + case tpnme.BitwiseAnd => constantFold2(intValue, _ & _) + case tpnme.BitwiseOr => constantFold2(intValue, _ | _) + case tpnme.ASR => constantFold2(intValue, _ >> _) + case tpnme.LSL => constantFold2(intValue, _ << _) + case tpnme.LSR => constantFold2(intValue, _ >>> _) + case tpnme.Min => constantFold2(intValue, _ min _) + case tpnme.Max => constantFold2(intValue, _ max _) + case tpnme.NumberOfLeadingZeros => constantFold1(intValue, Integer.numberOfLeadingZeros(_)) + case tpnme.ToLong => constantFold1(intValue, _.toLong) + case tpnme.ToFloat => constantFold1(intValue, _.toFloat) + case tpnme.ToDouble => constantFold1(intValue, _.toDouble) case _ => None } else if (owner == defn.CompiletimeOpsLongModuleClass) name match { - case tpnme.Abs if nArgs == 1 => constantFold1(longValue, _.abs) - case tpnme.Negate if nArgs == 1 => constantFold1(longValue, x => -x) - case tpnme.Plus if nArgs == 2 => constantFold2(longValue, _ + _) - case tpnme.Minus if nArgs == 2 => constantFold2(longValue, _ - _) - case tpnme.Times if nArgs == 2 => constantFold2(longValue, _ * _) - case tpnme.Div if nArgs == 2 => constantFold2(longValue, { - case (_, 0L) => throw new TypeError("Division by 0") - case (a, b) => a / b - }) - case tpnme.Mod if nArgs == 2 => constantFold2(longValue, { - case (_, 0L) => throw new TypeError("Modulo by 0") - case (a, b) => a % b - }) - case tpnme.Lt if nArgs == 2 => constantFold2(longValue, _ < _) - case tpnme.Gt if nArgs == 2 => constantFold2(longValue, _ > _) - case tpnme.Ge if nArgs == 2 => constantFold2(longValue, _ >= _) - case tpnme.Le if nArgs == 2 => constantFold2(longValue, _ <= _) - case tpnme.Xor if nArgs == 2 => constantFold2(longValue, _ ^ _) - case tpnme.BitwiseAnd if nArgs == 2 => constantFold2(longValue, _ & _) - case tpnme.BitwiseOr if nArgs == 2 => constantFold2(longValue, _ | _) - case tpnme.ASR if nArgs == 2 => constantFold2(longValue, _ >> _) - case tpnme.LSL if nArgs == 2 => constantFold2(longValue, _ << _) - case tpnme.LSR if nArgs == 2 => constantFold2(longValue, _ >>> _) - case tpnme.Min if nArgs == 2 => constantFold2(longValue, _ min _) - case tpnme.Max if nArgs == 2 => constantFold2(longValue, _ max _) - case tpnme.NumberOfLeadingZeros if nArgs == 1 => + case tpnme.Abs => constantFold1(longValue, _.abs) + case tpnme.Negate => constantFold1(longValue, x => -x) + case tpnme.Plus => constantFold2(longValue, _ + _) + case tpnme.Minus => constantFold2(longValue, _ - _) + case tpnme.Times => constantFold2(longValue, _ * _) + case tpnme.Div => constantFold2(longValue, _ / _) + case tpnme.Mod => constantFold2(longValue, _ % _) + case tpnme.Lt => constantFold2(longValue, _ < _) + case tpnme.Gt => constantFold2(longValue, _ > _) + case tpnme.Ge => constantFold2(longValue, _ >= _) + case tpnme.Le => constantFold2(longValue, _ <= _) + case tpnme.Xor => constantFold2(longValue, _ ^ _) + case tpnme.BitwiseAnd => constantFold2(longValue, _ & _) + case tpnme.BitwiseOr => constantFold2(longValue, _ | _) + case tpnme.ASR => constantFold2(longValue, _ >> _) + case tpnme.LSL => constantFold2(longValue, _ << _) + case tpnme.LSR => constantFold2(longValue, _ >>> _) + case tpnme.Min => constantFold2(longValue, _ min _) + case tpnme.Max => constantFold2(longValue, _ max _) + case tpnme.NumberOfLeadingZeros => constantFold1(longValue, java.lang.Long.numberOfLeadingZeros(_)) - case tpnme.ToInt if nArgs == 1 => constantFold1(longValue, _.toInt) - case tpnme.ToFloat if nArgs == 1 => constantFold1(longValue, _.toFloat) - case tpnme.ToDouble if nArgs == 1 => constantFold1(longValue, _.toDouble) + case tpnme.ToInt => constantFold1(longValue, _.toInt) + case tpnme.ToFloat => constantFold1(longValue, _.toFloat) + case tpnme.ToDouble => constantFold1(longValue, _.toDouble) case _ => None } else if (owner == defn.CompiletimeOpsFloatModuleClass) name match { - case tpnme.Abs if nArgs == 1 => constantFold1(floatValue, _.abs) - case tpnme.Negate if nArgs == 1 => constantFold1(floatValue, x => -x) - case tpnme.Plus if nArgs == 2 => constantFold2(floatValue, _ + _) - case tpnme.Minus if nArgs == 2 => constantFold2(floatValue, _ - _) - case tpnme.Times if nArgs == 2 => constantFold2(floatValue, _ * _) - case tpnme.Div if nArgs == 2 => constantFold2(floatValue, _ / _) - case tpnme.Mod if nArgs == 2 => constantFold2(floatValue, _ % _) - case tpnme.Lt if nArgs == 2 => constantFold2(floatValue, _ < _) - case tpnme.Gt if nArgs == 2 => constantFold2(floatValue, _ > _) - case tpnme.Ge if nArgs == 2 => constantFold2(floatValue, _ >= _) - case tpnme.Le if nArgs == 2 => constantFold2(floatValue, _ <= _) - case tpnme.Min if nArgs == 2 => constantFold2(floatValue, _ min _) - case tpnme.Max if nArgs == 2 => constantFold2(floatValue, _ max _) - case tpnme.ToInt if nArgs == 1 => constantFold1(floatValue, _.toInt) - case tpnme.ToLong if nArgs == 1 => constantFold1(floatValue, _.toLong) - case tpnme.ToDouble if nArgs == 1 => constantFold1(floatValue, _.toDouble) + case tpnme.Abs => constantFold1(floatValue, _.abs) + case tpnme.Negate => constantFold1(floatValue, x => -x) + case tpnme.Plus => constantFold2(floatValue, _ + _) + case tpnme.Minus => constantFold2(floatValue, _ - _) + case tpnme.Times => constantFold2(floatValue, _ * _) + case tpnme.Div => constantFold2(floatValue, _ / _) + case tpnme.Mod => constantFold2(floatValue, _ % _) + case tpnme.Lt => constantFold2(floatValue, _ < _) + case tpnme.Gt => constantFold2(floatValue, _ > _) + case tpnme.Ge => constantFold2(floatValue, _ >= _) + case tpnme.Le => constantFold2(floatValue, _ <= _) + case tpnme.Min => constantFold2(floatValue, _ min _) + case tpnme.Max => constantFold2(floatValue, _ max _) + case tpnme.ToInt => constantFold1(floatValue, _.toInt) + case tpnme.ToLong => constantFold1(floatValue, _.toLong) + case tpnme.ToDouble => constantFold1(floatValue, _.toDouble) case _ => None } else if (owner == defn.CompiletimeOpsDoubleModuleClass) name match { - case tpnme.Abs if nArgs == 1 => constantFold1(doubleValue, _.abs) - case tpnme.Negate if nArgs == 1 => constantFold1(doubleValue, x => -x) - case tpnme.Plus if nArgs == 2 => constantFold2(doubleValue, _ + _) - case tpnme.Minus if nArgs == 2 => constantFold2(doubleValue, _ - _) - case tpnme.Times if nArgs == 2 => constantFold2(doubleValue, _ * _) - case tpnme.Div if nArgs == 2 => constantFold2(doubleValue, _ / _) - case tpnme.Mod if nArgs == 2 => constantFold2(doubleValue, _ % _) - case tpnme.Lt if nArgs == 2 => constantFold2(doubleValue, _ < _) - case tpnme.Gt if nArgs == 2 => constantFold2(doubleValue, _ > _) - case tpnme.Ge if nArgs == 2 => constantFold2(doubleValue, _ >= _) - case tpnme.Le if nArgs == 2 => constantFold2(doubleValue, _ <= _) - case tpnme.Min if nArgs == 2 => constantFold2(doubleValue, _ min _) - case tpnme.Max if nArgs == 2 => constantFold2(doubleValue, _ max _) - case tpnme.ToInt if nArgs == 1 => constantFold1(doubleValue, _.toInt) - case tpnme.ToLong if nArgs == 1 => constantFold1(doubleValue, _.toLong) - case tpnme.ToFloat if nArgs == 1 => constantFold1(doubleValue, _.toFloat) + case tpnme.Abs => constantFold1(doubleValue, _.abs) + case tpnme.Negate => constantFold1(doubleValue, x => -x) + case tpnme.Plus => constantFold2(doubleValue, _ + _) + case tpnme.Minus => constantFold2(doubleValue, _ - _) + case tpnme.Times => constantFold2(doubleValue, _ * _) + case tpnme.Div => constantFold2(doubleValue, _ / _) + case tpnme.Mod => constantFold2(doubleValue, _ % _) + case tpnme.Lt => constantFold2(doubleValue, _ < _) + case tpnme.Gt => constantFold2(doubleValue, _ > _) + case tpnme.Ge => constantFold2(doubleValue, _ >= _) + case tpnme.Le => constantFold2(doubleValue, _ <= _) + case tpnme.Min => constantFold2(doubleValue, _ min _) + case tpnme.Max => constantFold2(doubleValue, _ max _) + case tpnme.ToInt => constantFold1(doubleValue, _.toInt) + case tpnme.ToLong => constantFold1(doubleValue, _.toLong) + case tpnme.ToFloat => constantFold1(doubleValue, _.toFloat) case _ => None } else if (owner == defn.CompiletimeOpsStringModuleClass) name match { - case tpnme.Plus if nArgs == 2 => constantFold2(stringValue, _ + _) - case tpnme.Length if nArgs == 1 => constantFold1(stringValue, _.length) - case tpnme.Matches if nArgs == 2 => constantFold2(stringValue, _ matches _) - case tpnme.Substring if nArgs == 3 => + case tpnme.Plus => constantFold2(stringValue, _ + _) + case tpnme.Length => constantFold1(stringValue, _.length) + case tpnme.Matches => constantFold2(stringValue, _ matches _) + case tpnme.Substring => constantFold3(stringValue, intValue, intValue, (s, b, e) => s.substring(b, e)) case _ => None } else if (owner == defn.CompiletimeOpsBooleanModuleClass) name match { - case tpnme.Not if nArgs == 1 => constantFold1(boolValue, x => !x) - case tpnme.And if nArgs == 2 => constantFold2(boolValue, _ && _) - case tpnme.Or if nArgs == 2 => constantFold2(boolValue, _ || _) - case tpnme.Xor if nArgs == 2 => constantFold2(boolValue, _ ^ _) + case tpnme.Not => constantFold1(boolValue, x => !x) + case tpnme.And => constantFold2(boolValue, _ && _) + case tpnme.Or => constantFold2(boolValue, _ || _) + case tpnme.Xor => constantFold2(boolValue, _ ^ _) case _ => None } else None From 23de5cdb0661dcfa89fd133f22c3d93515264eeb Mon Sep 17 00:00:00 2001 From: oronpo Date: Mon, 25 Oct 2021 21:10:02 -0400 Subject: [PATCH 0853/1244] improve `any.IsConst` to be evaluated only if its argument is concrete and known --- .../src/dotty/tools/dotc/core/Types.scala | 35 ++++++++++++++++--- library/src/scala/compiletime/ops/any.scala | 9 +++++ tests/neg/singleton-ops-any.scala | 8 ++++- 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index aa68f4cacad1..287030136b00 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -4252,9 +4252,36 @@ object Types { case _ => None } - def isConst(tp : Type) : Option[Type] = tp.fixForEvaluation match { - case ConstantType(_) => Some(ConstantType(Constant(true))) - case _ => Some(ConstantType(Constant(false))) + val opsSet = Set( + defn.CompiletimeOpsAnyModuleClass, + defn.CompiletimeOpsIntModuleClass, + defn.CompiletimeOpsLongModuleClass, + defn.CompiletimeOpsFloatModuleClass, + defn.CompiletimeOpsBooleanModuleClass, + defn.CompiletimeOpsStringModuleClass + ) + + //Returns Some(true) if the type is a constant. + //Returns Some(false) if the type is not a constant. + //Returns None if there is not enough information to determine if the type is a constant. + //The type is a constant if it is a constant type or a type operation composition of constant types. + //If we get a type reference for an argument, then the result is not yet known. + def isConst(tp : Type) : Option[Boolean] = tp.dealias match { + //known to be constant + case ConstantType(_) => Some(true) + //currently not a concrete known type + case TypeRef(NoPrefix,_) => None + //currently not a concrete known type + case _ : TypeParamRef => None + //constant if the term is constant + case t : TermRef => isConst(t.underlying) + //an operation type => recursively check all argument compositions + case applied : AppliedType if opsSet.contains(applied.typeSymbol.owner) => + val argsConst = applied.args.map(isConst) + if (argsConst.exists(_.isEmpty)) None + else Some(argsConst.forall(_.get)) + //all other types are considered not to be constant + case _ => Some(false) } def expectArgsNum(expectedNum : Int) : Unit = @@ -4312,7 +4339,7 @@ object Types { case tpnme.Equals => constantFold2(constValue, _ == _) case tpnme.NotEquals => constantFold2(constValue, _ != _) case tpnme.ToString => constantFold1(constValue, _.toString) - case tpnme.IsConst => isConst(args.head) + case tpnme.IsConst => isConst(args.head).map(b => ConstantType(Constant(b))) case _ => None } else if (owner == defn.CompiletimeOpsIntModuleClass) name match { case tpnme.Abs => constantFold1(intValue, _.abs) diff --git a/library/src/scala/compiletime/ops/any.scala b/library/src/scala/compiletime/ops/any.scala index 60b86414a385..56605979474d 100644 --- a/library/src/scala/compiletime/ops/any.scala +++ b/library/src/scala/compiletime/ops/any.scala @@ -29,6 +29,15 @@ object any: * val c1: IsConst[1] = true * val c2: IsConst["hi"] = true * val c3: IsConst[false] = true + * val c4: IsConst[Any] = false + * ``` + * If the type is not yet known, then `IsConst` remains unevaluated, and + * will be evaluated only at its concrete type application. E.g.: + * ```scala + * //def `isConst`` returns the type `IsConst[X]`, since `X` is not yet known. + * def isConst[X] : IsConst[X] = ??? + * val c5 : true = isConst[1] //now the type is known to be a constant + * val c6 : false = isConst[Any] //now the type is known to be not a constant * ``` * @syntax markdown */ diff --git a/tests/neg/singleton-ops-any.scala b/tests/neg/singleton-ops-any.scala index 33951f58bcd9..45f63cf68ff1 100644 --- a/tests/neg/singleton-ops-any.scala +++ b/tests/neg/singleton-ops-any.scala @@ -30,5 +30,11 @@ object Test { final val two = 2 val t47 : IsConst[two.type] = true val t48: IsConst[Any] = true // error - + def isConst[X] : IsConst[X] = ??? + val t49 : true = isConst[1] + val t50 : false = isConst[one.type] + def isConst2[X <: Int, Y <: Int] : IsConst[X == Y] = ??? + val t51 : true = isConst2[1, 1] + val t52 : false = isConst2[1, one.type] + val t53 : true = isConst2[1, two.type] } From 621adef983486b363f9dac856fda37cfd104fb99 Mon Sep 17 00:00:00 2001 From: oronpo Date: Mon, 25 Oct 2021 21:44:16 -0400 Subject: [PATCH 0854/1244] Fix documentation errors. Remove redundant `long.ToString` --- library/src/scala/compiletime/ops/double.scala | 6 +++--- library/src/scala/compiletime/ops/float.scala | 6 +++--- library/src/scala/compiletime/ops/long.scala | 14 +++----------- library/src/scala/compiletime/ops/string.scala | 2 +- 4 files changed, 10 insertions(+), 18 deletions(-) diff --git a/library/src/scala/compiletime/ops/double.scala b/library/src/scala/compiletime/ops/double.scala index e06ff64c3f05..e9b13ab9dcd6 100644 --- a/library/src/scala/compiletime/ops/double.scala +++ b/library/src/scala/compiletime/ops/double.scala @@ -31,7 +31,7 @@ object double: /** Integer division of two `Double` singleton types. * ```scala - * val div: 5.0 / 2.0 = 2.0 + * val div: 5.0 / 2.0 = 2.5 * ``` * @syntax markdown */ @@ -91,8 +91,8 @@ object double: /** Negation of an `Double` singleton type. * ```scala - * val neg1: Neg[-1.0] = 1.0 - * val neg2: Neg[1.0] = -1.0 + * val neg1: Negate[-1.0] = 1.0 + * val neg2: Negate[1.0] = -1.0 * ``` * @syntax markdown */ diff --git a/library/src/scala/compiletime/ops/float.scala b/library/src/scala/compiletime/ops/float.scala index d5aeb2d5f4f7..27a1a19c17c1 100644 --- a/library/src/scala/compiletime/ops/float.scala +++ b/library/src/scala/compiletime/ops/float.scala @@ -31,7 +31,7 @@ object float: /** Integer division of two `Float` singleton types. * ```scala - * val div: 5.0f / 2.0f = 2.0f + * val div: 5.0f / 2.0f = 2.5f * ``` * @syntax markdown */ @@ -91,8 +91,8 @@ object float: /** Negation of an `Float` singleton type. * ```scala - * val neg1: Neg[-1.0f] = 1.0f - * val neg2: Neg[1.0f] = -1.0f + * val neg1: Negate[-1.0f] = 1.0f + * val neg2: Negate[1.0f] = -1.0f * ``` * @syntax markdown */ diff --git a/library/src/scala/compiletime/ops/long.scala b/library/src/scala/compiletime/ops/long.scala index f3158e12c2f6..92e6bd370f5b 100644 --- a/library/src/scala/compiletime/ops/long.scala +++ b/library/src/scala/compiletime/ops/long.scala @@ -12,7 +12,7 @@ object long: * case 0L => 1L * case 1L => 2L * case 2L => 3L - * ... + * // ... * case 9223372036854775806L => 9223372036854775807L * } * ``` @@ -155,8 +155,8 @@ object long: /** Negation of an `Long` singleton type. * ```scala - * val neg1: Neg[-1L] = 1L - * val neg2: Neg[1L] = -1L + * val neg1: Negate[-1L] = 1L + * val neg2: Negate[1L] = -1L * ``` * @syntax markdown */ @@ -178,14 +178,6 @@ object long: */ type Max[X <: Long, Y <: Long] <: Long - /** String conversion of an `Long` singleton type. - * ```scala - * val abs: ToString[1L] = "1" - * ``` - * @syntax markdown - */ - type ToString[X <: Long] <: String - /** Number of zero bits preceding the highest-order ("leftmost") * one-bit in the two's complement binary representation of the specified `Long` singleton type. * Returns 64 if the specified singleton type has no one-bits in its two's complement representation, diff --git a/library/src/scala/compiletime/ops/string.scala b/library/src/scala/compiletime/ops/string.scala index 51e336ab7adc..6214f983db32 100644 --- a/library/src/scala/compiletime/ops/string.scala +++ b/library/src/scala/compiletime/ops/string.scala @@ -14,7 +14,7 @@ object string: /** Length of a `String` singleton type. * ```scala - * val helloSize: Size["hello"] = 5 + * val helloSize: Length["hello"] = 5 * ``` * @syntax markdown */ From b2b12a69d660abf2bd92bcc6e7a9d1c22fb207b0 Mon Sep 17 00:00:00 2001 From: Olivier Blanvillain Date: Wed, 17 Nov 2021 17:43:36 +0100 Subject: [PATCH 0855/1244] Fix code formatting --- .../dotty/tools/dotc/core/Definitions.scala | 2 +- .../src/dotty/tools/dotc/core/Types.scala | 60 +++++++++---------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 1ee40f5d1830..19ddcf7b16fe 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -1090,7 +1090,7 @@ class Definitions { tpnme.Abs, tpnme.Negate, tpnme.Min, tpnme.Max ) private val compiletimePackageIntTypes: Set[Name] = compiletimePackageNumericTypes ++ Set[Name]( - tpnme.ToString, //ToString is moved to ops.any and deprecated for ops.int + tpnme.ToString, // ToString is moved to ops.any and deprecated for ops.int tpnme.NumberOfLeadingZeros, tpnme.ToLong, tpnme.ToFloat, tpnme.ToDouble, tpnme.Xor, tpnme.BitwiseAnd, tpnme.BitwiseOr, tpnme.ASR, tpnme.LSL, tpnme.LSR ) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 287030136b00..b1007a32f5c4 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -4206,14 +4206,14 @@ object Types { def tryCompiletimeConstantFold(using Context): Type = tycon match { case tycon: TypeRef if defn.isCompiletimeAppliedType(tycon.symbol) => - extension (tp : Type) def fixForEvaluation : Type = + extension (tp: Type) def fixForEvaluation: Type = tp.normalized.dealias match { - //enable operations for constant singleton terms. E.g.: - //``` - //final val one = 1 - //type Two = one.type + one.type - //``` - case tp : TermRef => tp.underlying + // enable operations for constant singleton terms. E.g.: + // ``` + // final val one = 1 + // type Two = one.type + one.type + // ``` + case tp: TermRef => tp.underlying case tp => tp } @@ -4261,43 +4261,43 @@ object Types { defn.CompiletimeOpsStringModuleClass ) - //Returns Some(true) if the type is a constant. - //Returns Some(false) if the type is not a constant. - //Returns None if there is not enough information to determine if the type is a constant. - //The type is a constant if it is a constant type or a type operation composition of constant types. - //If we get a type reference for an argument, then the result is not yet known. - def isConst(tp : Type) : Option[Boolean] = tp.dealias match { - //known to be constant + // Returns Some(true) if the type is a constant. + // Returns Some(false) if the type is not a constant. + // Returns None if there is not enough information to determine if the type is a constant. + // The type is a constant if it is a constant type or a type operation composition of constant types. + // If we get a type reference for an argument, then the result is not yet known. + def isConst(tp: Type): Option[Boolean] = tp.dealias match { + // known to be constant case ConstantType(_) => Some(true) - //currently not a concrete known type + // currently not a concrete known type case TypeRef(NoPrefix,_) => None - //currently not a concrete known type - case _ : TypeParamRef => None - //constant if the term is constant - case t : TermRef => isConst(t.underlying) - //an operation type => recursively check all argument compositions - case applied : AppliedType if opsSet.contains(applied.typeSymbol.owner) => + // currently not a concrete known type + case _: TypeParamRef => None + // constant if the term is constant + case t: TermRef => isConst(t.underlying) + // an operation type => recursively check all argument compositions + case applied: AppliedType if opsSet.contains(applied.typeSymbol.owner) => val argsConst = applied.args.map(isConst) if (argsConst.exists(_.isEmpty)) None else Some(argsConst.forall(_.get)) - //all other types are considered not to be constant + // all other types are considered not to be constant case _ => Some(false) } - def expectArgsNum(expectedNum : Int) : Unit = - //We can use assert instead of a compiler type error because this error should not - //occur since the type signature of the operation enforces the proper number of args. + def expectArgsNum(expectedNum: Int): Unit = + // We can use assert instead of a compiler type error because this error should not + // occur since the type signature of the operation enforces the proper number of args. assert(args.length == expectedNum, s"Type operation expects $expectedNum arguments but found ${args.length}") def natValue(tp: Type): Option[Int] = intValue(tp).filter(n => n >= 0 && n < Int.MaxValue) - //Runs the op and returns the result as a constant type. - //If the op throws an exception, then this exception is converted into a type error. - def runConstantOp(op : => Any): Type = + // Runs the op and returns the result as a constant type. + // If the op throws an exception, then this exception is converted into a type error. + def runConstantOp(op: => Any): Type = val result = try { op } catch { - case e : Throwable => + case e: Throwable => throw new TypeError(e.getMessage) } ConstantType(Constant(result)) @@ -4344,7 +4344,7 @@ object Types { } else if (owner == defn.CompiletimeOpsIntModuleClass) name match { case tpnme.Abs => constantFold1(intValue, _.abs) case tpnme.Negate => constantFold1(intValue, x => -x) - //ToString is deprecated for ops.int, and moved to ops.any + // ToString is deprecated for ops.int, and moved to ops.any case tpnme.ToString => constantFold1(intValue, _.toString) case tpnme.Plus => constantFold2(intValue, _ + _) case tpnme.Minus => constantFold2(intValue, _ - _) From 77784819e638dae12a85db8be72f3c06c328ef07 Mon Sep 17 00:00:00 2001 From: Oron Port Date: Mon, 22 Nov 2021 12:04:50 +0200 Subject: [PATCH 0856/1244] Add missing colon --- library/src/scala/compiletime/ops/long.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/scala/compiletime/ops/long.scala b/library/src/scala/compiletime/ops/long.scala index 92e6bd370f5b..718dec710068 100644 --- a/library/src/scala/compiletime/ops/long.scala +++ b/library/src/scala/compiletime/ops/long.scala @@ -5,7 +5,7 @@ import scala.annotation.experimental @experimental object long: - /** Successor of a natural number where zero is the type 0 and successors are reduced as if the definition was + /** Successor of a natural number where zero is the type 0 and successors are reduced as if the definition was: * * ```scala * type S[N <: Long] <: Long = N match { From 5f7a97be39dcdc048d60762515a37cccd3d61966 Mon Sep 17 00:00:00 2001 From: Oron Port Date: Mon, 22 Nov 2021 12:05:27 +0200 Subject: [PATCH 0857/1244] Add missing colon --- library/src/scala/compiletime/ops/int.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/src/scala/compiletime/ops/int.scala b/library/src/scala/compiletime/ops/int.scala index 8d62b98a27e4..3776e9e0d0d0 100644 --- a/library/src/scala/compiletime/ops/int.scala +++ b/library/src/scala/compiletime/ops/int.scala @@ -4,7 +4,7 @@ package ops import annotation.experimental object int: - /** Successor of a natural number where zero is the type 0 and successors are reduced as if the definition was + /** Successor of a natural number where zero is the type 0 and successors are reduced as if the definition was: * * ```scala * type S[N <: Int] <: Int = N match { @@ -226,4 +226,4 @@ object int: * @syntax markdown */ @experimental - type NumberOfLeadingZeros[X <: Int] <: Int \ No newline at end of file + type NumberOfLeadingZeros[X <: Int] <: Int From 5985dd1e71fe641f3459a525d32322b3f54072d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Zyba=C5=82a?= Date: Wed, 10 Nov 2021 12:11:32 +0100 Subject: [PATCH 0858/1244] Fix links to unexisting types sites --- project/Build.scala | 20 +++++++++------- .../scaladoc/tasty/ClassLikeSupport.scala | 24 ++++++++++--------- .../tools/scaladoc/tasty/TypesSupport.scala | 4 +++- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/project/Build.scala b/project/Build.scala index adbedca984dd..6d5bef45aff4 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -319,10 +319,11 @@ object Build { private lazy val currentYear: String = java.util.Calendar.getInstance().get(java.util.Calendar.YEAR).toString - lazy val scalacOptionsDocSettings = Seq( - "-external-mappings:" + - ".*scala/.*::scaladoc3::https://dotty.epfl.ch/api/," + - ".*java/.*::javadoc::https://docs.oracle.com/javase/8/docs/api/", + def scalacOptionsDocSettings(includeExternalMappings: Boolean = true) = { + val extMap = Seq("-external-mappings:" + + (if (includeExternalMappings) ".*scala/.*::scaladoc3::https://dotty.epfl.ch/api/," else "") + + ".*java/.*::javadoc::https://docs.oracle.com/javase/8/docs/api/") + Seq( "-skip-by-regex:.+\\.internal($|\\..+)", "-skip-by-regex:.+\\.impl($|\\..+)", "-project-logo", "docs/logo.svg", @@ -340,7 +341,8 @@ object Build { "-project-footer", s"Copyright (c) 2002-$currentYear, LAMP/EPFL", "-author", "-groups" - ) + ) ++ extMap + } // Settings used when compiling dotty with a non-bootstrapped dotty lazy val commonBootstrappedSettings = commonDottySettings ++ NoBloopExport.settings ++ Seq( @@ -423,7 +425,7 @@ object Build { assert(docScalaInstance.loaderCompilerOnly == base.loaderCompilerOnly) docScalaInstance }, - Compile / doc / scalacOptions ++= scalacOptionsDocSettings + Compile / doc / scalacOptions ++= scalacOptionsDocSettings() ) lazy val commonBenchmarkSettings = Seq( @@ -1266,7 +1268,7 @@ object Build { libraryDependencies += ("org.scala-js" %%% "scalajs-dom" % "1.1.0").cross(CrossVersion.for3Use2_13) ) - def generateDocumentation(targets: Seq[String], name: String, outDir: String, ref: String, params: Seq[String] = Nil) = + def generateDocumentation(targets: Seq[String], name: String, outDir: String, ref: String, params: Seq[String] = Nil, includeExternalMappings: Boolean = true) = Def.taskDyn { val distLocation = (dist / pack).value val projectVersion = version.value @@ -1294,7 +1296,7 @@ object Build { dottySrcLink(referenceVersion, srcManaged(dottyNonBootstrappedVersion, "dotty") + "=", "#library/src"), dottySrcLink(referenceVersion), "-Ygenerate-inkuire", - ) ++ scalacOptionsDocSettings ++ revision ++ params ++ targets + ) ++ scalacOptionsDocSettings(includeExternalMappings) ++ revision ++ params ++ targets import _root_.scala.sys.process._ val escapedCmd = cmd.map(arg => if(arg.contains(" ")) s""""$arg"""" else arg) Def.task { @@ -1424,7 +1426,7 @@ object Build { "https://scala-lang.org/api/versions.json", "-Ydocument-synthetic-types", s"-snippet-compiler:${dottyLibRoot}/scala/quoted=compile,${dottyLibRoot}/scala/compiletime=compile" - ) ++ (if (justAPI) Nil else Seq("-siteroot", "docs-for-dotty-page", "-Yapi-subdirectory"))) + ) ++ (if (justAPI) Nil else Seq("-siteroot", "docs-for-dotty-page", "-Yapi-subdirectory")), includeExternalMappings = false) if (dottyJars.isEmpty) Def.task { streams.value.log.error("Dotty lib wasn't found") } else if (justAPI) generateDocTask diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala index d64aa8d67874..0ff21cda60c1 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala @@ -70,19 +70,21 @@ trait ClassLikeSupport: case tree: ClassDef => tree case tt: TypeTree => unpackTreeToClassDef(tt.tpe.typeSymbol.tree) - def getSupertypesGraph(classDef: Tree, link: LinkToType): Seq[(LinkToType, LinkToType)] = - val smbl = classDef.symbol - val parents = unpackTreeToClassDef(classDef).parents - parents.flatMap { case tree => + def getSupertypesGraph(link: LinkToType, to: Seq[Tree]): Seq[(LinkToType, LinkToType)] = + to.flatMap { case tree => val symbol = if tree.symbol.isClassConstructor then tree.symbol.owner else tree.symbol val superLink = LinkToType(tree.asSignature, symbol.dri, bareClasslikeKind(symbol)) - Seq(link -> superLink) ++ getSupertypesGraph(tree, superLink) + val nextTo = unpackTreeToClassDef(tree).parents + if symbol.isHiddenByVisibility then getSupertypesGraph(link, nextTo) + else Seq(link -> superLink) ++ getSupertypesGraph(superLink, nextTo) } - val supertypes = getSupertypes(using qctx)(classDef).map { - case (symbol, tpe) => - LinkToType(tpe.asSignature, symbol.dri, bareClasslikeKind(symbol)) - } + val supertypes = getSupertypes(using qctx)(classDef) + .filterNot((s, t) => s.isHiddenByVisibility) + .map { + case (symbol, tpe) => + LinkToType(tpe.asSignature, symbol.dri, bareClasslikeKind(symbol)) + } val selfType = classDef.self.map { (valdef: ValDef) => val symbol = valdef.symbol val tpe = valdef.tpt.tpe @@ -91,7 +93,7 @@ trait ClassLikeSupport: val selfSignature: DSignature = typeForClass(classDef).asSignature val graph = HierarchyGraph.withEdges( - getSupertypesGraph(classDef, LinkToType(selfSignature, classDef.symbol.dri, bareClasslikeKind(classDef.symbol))) + getSupertypesGraph(LinkToType(selfSignature, classDef.symbol.dri, bareClasslikeKind(classDef.symbol)), unpackTreeToClassDef(classDef).parents) ) val baseMember = mkMember(classDef.symbol, kindForClasslike(classDef), selfSignature)( @@ -255,7 +257,7 @@ trait ClassLikeSupport: case t: TypeTree => t.tpe.typeSymbol case tree if tree.symbol.isClassConstructor => tree.symbol.owner case tree => tree.symbol - if parentSymbol != defn.ObjectClass && parentSymbol != defn.AnyClass + if parentSymbol != defn.ObjectClass && parentSymbol != defn.AnyClass && !parentSymbol.isHiddenByVisibility yield (parentTree, parentSymbol) def getConstructors: List[Symbol] = c.membersToDocument.collect { diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/TypesSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/TypesSupport.scala index 147b5c40d21b..d825b7ab6c31 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/TypesSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/TypesSupport.scala @@ -61,8 +61,10 @@ trait TypesSupport: extension (on: SignaturePart) def l: List[SignaturePart] = List(on) private def tpe(using Quotes)(symbol: reflect.Symbol): SSignature = + import SymOps._ val suffix = if symbol.isValDef || symbol.flags.is(reflect.Flags.Module) then plain(".type").l else Nil - dotty.tools.scaladoc.Type(symbol.normalizedName, Some(symbol.dri)) :: suffix + val dri: Option[DRI] = Option(symbol).filterNot(_.isHiddenByVisibility).map(_.dri) + dotty.tools.scaladoc.Type(symbol.normalizedName, dri) :: suffix private def commas(lists: List[SSignature]) = lists match case List(single) => single From afbd0f8beed5967758fb5e7f78139098e6d6f13b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Wro=C5=84ski?= <46607934+lwronski@users.noreply.github.com> Date: Tue, 30 Nov 2021 10:13:14 +0100 Subject: [PATCH 0859/1244] Automate releases to SDKMAN (#13885) --- .github/workflows/releases.yml | 24 ++++++++++ .github/workflows/scripts/publish-sdkman.sh | 50 +++++++++++++++++++++ docs/docs/contributing/checklist.sh | 1 + 3 files changed, 75 insertions(+) create mode 100644 .github/workflows/releases.yml create mode 100755 .github/workflows/scripts/publish-sdkman.sh diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml new file mode 100644 index 000000000000..2bb6d3e49282 --- /dev/null +++ b/.github/workflows/releases.yml @@ -0,0 +1,24 @@ +name: Releases +on: + workflow_dispatch: + +jobs: + publish_release: + runs-on: [self-hosted, Linux] + container: + image: lampepfl/dotty:2021-03-22 + options: --cpu-shares 4096 + + env: + SDKMAN_KEY: ${{ secrets.SDKMAN_KEY }} + SDKMAN_TOKEN: ${{ secrets.SDKMAN_TOKEN }} + + steps: + - name: Reset existing repo + run: git -c "http.https://github.com/.extraheader=" fetch --recurse-submodules=no "https://github.com/lampepfl/dotty" && git reset --hard FETCH_HEAD || true + + - name: Cleanup + run: .github/workflows/cleanup.sh + + - name: Publish to SDKMAN + run: .github/workflows/scripts/publish-sdkman.sh diff --git a/.github/workflows/scripts/publish-sdkman.sh b/.github/workflows/scripts/publish-sdkman.sh new file mode 100755 index 000000000000..07d35a72a65e --- /dev/null +++ b/.github/workflows/scripts/publish-sdkman.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash + +# This is script for publishing scala on SDKMAN. +# Script resolves the latest stable version of scala and then send REST request to SDKMAN Vendor API. +# It's releasing and announcing the release of scala on SDKMAN. +# +# Requirement: +# - the latest stable version of scala should be available in github artifacts + +set -u + +# latest stable dotty version +DOTTY_VERSION=$(curl -s https://api.github.com/repos/lampepfl/dotty/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') +DOTTY_URL="https://github.com/lampepfl/dotty/releases/download/$DOTTY_VERSION/scala3-$DOTTY_VERSION.zip" + +# checking if dotty version is available +if ! curl --output /dev/null --silent --head --fail "$DOTTY_URL"; then + echo "URL doesn't exist: $DOTTY_URL" + exit 1 +fi + +# Release a new Candidate Version +curl --silent --show-error --fail \ + -X POST \ + -H "Consumer-Key: $SDKMAN_KEY" \ + -H "Consumer-Token: $SDKMAN_TOKEN" \ + -H "Content-Type: application/json" \ + -H "Accept: application/json" \ + -d '{"candidate": "scala", "version": "'"$DOTTY_VERSION"'", "url": "'"$DOTTY_URL"'"}' \ + https://vendors.sdkman.io/release + +if [[ $? -ne 0 ]]; then + echo "Fail sending POST request to releasing scala on SDKMAN." + exit 1 +fi + +# Set DOTTY_VERSION as Default for Candidate +curl --silent --show-error --fail \ + -X PUT \ + -H "Consumer-Key: $SDKMAN_KEY" \ + -H "Consumer-Token: $SDKMAN_TOKEN" \ + -H "Content-Type: application/json" \ + -H "Accept: application/json" \ + -d '{"candidate": "scala", "version": "'"$DOTTY_VERSION"'"}' \ + https://vendors.sdkman.io/default + +if [[ $? -ne 0 ]]; then + echo "Fail sending PUT request to announcing the release of scala on SDKMAN." + exit 1 +fi diff --git a/docs/docs/contributing/checklist.sh b/docs/docs/contributing/checklist.sh index 827f0911d84d..d3cfe70b4e21 100755 --- a/docs/docs/contributing/checklist.sh +++ b/docs/docs/contributing/checklist.sh @@ -48,6 +48,7 @@ LIST='- [ ] Publish artifacts to Maven via CI - [ ] Publish Blog Post on dotty.epfl.ch - [ ] Make an announcement thread on https://contributors.scala-lang.org - [ ] Tweet the announcement blog post on https://twitter.com/scala_lang + - [ ] Run workflow releases CI to publish scala on SDKMAN - https://github.com/lampepfl/dotty/actions/workflows/releases.yml [Instructions on how to release](https://dotty.epfl.ch/docs/contributing/release.html)' From f9aa3be865d51b48ec2a3399755965e47578687f Mon Sep 17 00:00:00 2001 From: Andrzej Ratajczak <32793002+BarkingBad@users.noreply.github.com> Date: Tue, 30 Nov 2021 16:43:37 +0100 Subject: [PATCH 0860/1244] Scaladoc features parity with old scaladoc/docs.scala-lang (#13954) * POC * Walk in order and collect previous/next * Add `Edit on Github` button and `Contriubuted` sections * Polish gathering the contributors. CSSes fixes. * Fix tooltipping snippets * Fix handling relative links for static site * Add redirects mechanism for scaladoc * Fix leftover * Fix tests * Fix gathering index html for sections without explicit index * Apply requested changes to scaladoc * Decouple Scala.js jses. Move contributors to be independent asset/ * Add support for multiple redirects * Apply requested changes. Add static site for testcases. Fix minor bugs in scaladoc. * Fix tests --- .github/workflows/scaladoc.yaml | 2 +- build.sbt | 5 +- docs/_layouts/blog-page.html | 4 +- docs/_layouts/doc-page.html | 25 +++-- docs/_layouts/main.html | 11 +- docs/_layouts/redirect.html | 14 +++ docs/_layouts/static-site-main.html | 49 +++++++++ docs/blog/index.html | 2 +- docs/css/dottydoc.css | 6 +- .../reference/experimental/named-typeargs.md | 1 + .../other-new-features/named-typeargs.md | 7 -- project/Build.scala | 102 ++++++++---------- project/CopyDocs.scala | 46 ++++---- project/DocumentationWebsite.scala | 85 +++++++++++++++ project/scripts/cmdScaladocTests | 1 + .../css}/code-snippets.css | 10 +- .../{resources => common/css}/searchbar.css | 0 .../css}/social-links.css | 0 scaladoc-js/{resources => common/css}/ux.css | 0 .../css}/versions-dropdown.css | 0 .../src/code-snippets/CodeSnippets.scala | 0 .../code-snippets/CodeSnippetsGlobals.scala | 0 .../src/code-snippets/Scastie.scala | 0 .../contributors/css/content-contributors.css | 24 +++++ scaladoc-js/contributors/src/Globals.scala | 11 ++ scaladoc-js/contributors/src/Main.scala | 5 + .../ContentContributors.scala | 78 ++++++++++++++ scaladoc-js/{ => main}/src/Globals.scala | 0 scaladoc-js/main/src/Main.scala | 10 ++ .../{ => main}/src/searchbar/PageEntry.scala | 0 .../{ => main}/src/searchbar/Searchbar.scala | 0 .../src/searchbar/SearchbarComponent.scala | 0 .../src/searchbar/SearchbarGlobals.scala | 0 .../engine/InkuireJSSearchEngine.scala | 0 .../src/searchbar/engine/Matchers.scala | 0 .../src/searchbar/engine/QueryParser.scala | 0 .../searchbar/engine/SearchbarEngine.scala | 0 .../src/social-links/SocialLinks.scala | 0 .../TooltipNormalizer.scala | 25 +++++ scaladoc-js/{ => main}/src/ux/Ux.scala | 0 .../versions-dropdown/DropdownHandler.scala | 0 .../dotty/tools/scaladoc}/MatchersTest.scala | 0 .../tools/scaladoc}/QueryParserTest.scala | 2 +- scaladoc-js/markdown/src/Main.scala | 5 + scaladoc-js/src/Main.scala | 22 ---- .../docs/_layouts/redirect.html | 14 +++ .../docs/_layouts/static-site-main.html | 22 ++++ scaladoc-testcases/docs/css/bootstrap.min.css | 1 + scaladoc-testcases/docs/docs/docs/f1.md | 7 ++ scaladoc-testcases/docs/docs/docs/f2.md | 4 + scaladoc-testcases/docs/docs/docs/f3.md | 4 + scaladoc-testcases/docs/docs/docs/f4.md | 4 + scaladoc-testcases/docs/sidebar.yml | 7 ++ .../resources/dotty_res/styles/scalastyle.css | 86 +++++++++++++-- .../src/dotty/tools/scaladoc/Scaladoc.scala | 2 + .../tools/scaladoc/ScaladocSettings.scala | 10 ++ .../dotty/tools/scaladoc/SourceLinks.scala | 22 +++- .../scaladoc/renderers/HtmlRenderer.scala | 14 ++- .../tools/scaladoc/renderers/Renderer.scala | 48 ++++++++- .../scaladoc/renderers/SiteRenderer.scala | 2 +- .../tools/scaladoc/site/LoadedTemplate.scala | 9 +- .../scaladoc/site/StaticSiteContext.scala | 73 +++++++++---- .../dotty/tools/scaladoc/site/templates.scala | 10 +- .../comments/markdown/SnippetRenderer.scala | 2 +- .../dotty/tools/scaladoc/ReportingTest.scala | 2 +- 65 files changed, 718 insertions(+), 177 deletions(-) create mode 100644 docs/_layouts/redirect.html create mode 100644 docs/_layouts/static-site-main.html delete mode 100644 docs/docs/reference/other-new-features/named-typeargs.md create mode 100644 project/DocumentationWebsite.scala rename scaladoc-js/{resources => common/css}/code-snippets.css (97%) rename scaladoc-js/{resources => common/css}/searchbar.css (100%) rename scaladoc-js/{resources => common/css}/social-links.css (100%) rename scaladoc-js/{resources => common/css}/ux.css (100%) rename scaladoc-js/{resources => common/css}/versions-dropdown.css (100%) rename scaladoc-js/{ => common}/src/code-snippets/CodeSnippets.scala (100%) rename scaladoc-js/{ => common}/src/code-snippets/CodeSnippetsGlobals.scala (100%) rename scaladoc-js/{ => common}/src/code-snippets/Scastie.scala (100%) create mode 100644 scaladoc-js/contributors/css/content-contributors.css create mode 100644 scaladoc-js/contributors/src/Globals.scala create mode 100644 scaladoc-js/contributors/src/Main.scala create mode 100644 scaladoc-js/contributors/src/content-contributors/ContentContributors.scala rename scaladoc-js/{ => main}/src/Globals.scala (100%) create mode 100644 scaladoc-js/main/src/Main.scala rename scaladoc-js/{ => main}/src/searchbar/PageEntry.scala (100%) rename scaladoc-js/{ => main}/src/searchbar/Searchbar.scala (100%) rename scaladoc-js/{ => main}/src/searchbar/SearchbarComponent.scala (100%) rename scaladoc-js/{ => main}/src/searchbar/SearchbarGlobals.scala (100%) rename scaladoc-js/{ => main}/src/searchbar/engine/InkuireJSSearchEngine.scala (100%) rename scaladoc-js/{ => main}/src/searchbar/engine/Matchers.scala (100%) rename scaladoc-js/{ => main}/src/searchbar/engine/QueryParser.scala (100%) rename scaladoc-js/{ => main}/src/searchbar/engine/SearchbarEngine.scala (100%) rename scaladoc-js/{ => main}/src/social-links/SocialLinks.scala (100%) create mode 100644 scaladoc-js/main/src/tooltip-normalizer/TooltipNormalizer.scala rename scaladoc-js/{ => main}/src/ux/Ux.scala (100%) rename scaladoc-js/{ => main}/src/versions-dropdown/DropdownHandler.scala (100%) rename scaladoc-js/{test/dotty/dokka => main/test/dotty/tools/scaladoc}/MatchersTest.scala (100%) rename scaladoc-js/{test/dotty/dokka => main/test/dotty/tools/scaladoc}/QueryParserTest.scala (99%) create mode 100644 scaladoc-js/markdown/src/Main.scala delete mode 100644 scaladoc-js/src/Main.scala create mode 100644 scaladoc-testcases/docs/_layouts/redirect.html create mode 100644 scaladoc-testcases/docs/_layouts/static-site-main.html create mode 100644 scaladoc-testcases/docs/css/bootstrap.min.css create mode 100644 scaladoc-testcases/docs/docs/docs/f1.md create mode 100644 scaladoc-testcases/docs/docs/docs/f2.md create mode 100644 scaladoc-testcases/docs/docs/docs/f3.md create mode 100644 scaladoc-testcases/docs/docs/docs/f4.md create mode 100644 scaladoc-testcases/docs/sidebar.yml diff --git a/.github/workflows/scaladoc.yaml b/.github/workflows/scaladoc.yaml index dbe0628751c1..080b77fcb054 100644 --- a/.github/workflows/scaladoc.yaml +++ b/.github/workflows/scaladoc.yaml @@ -36,7 +36,7 @@ jobs: java-version: 11 - name: Compile and test scala3doc-js - run: ./project/scripts/sbt scaladoc-js/test + run: ./project/scripts/sbt scaladoc-js-main/test - name: Compile and test run: | diff --git a/build.sbt b/build.sbt index 81494a996bda..5add443e0a64 100644 --- a/build.sbt +++ b/build.sbt @@ -20,7 +20,10 @@ val `tasty-core-bootstrapped` = Build.`tasty-core-bootstrapped` val `tasty-core-scala2` = Build.`tasty-core-scala2` val scaladoc = Build.scaladoc val `scaladoc-testcases` = Build.`scaladoc-testcases` -val `scaladoc-js` = Build.`scaladoc-js` +val `scaladoc-js-common` = Build.`scaladoc-js-common` +val `scaladoc-js-main` = Build.`scaladoc-js-main` +val `scaladoc-js-markdown` = Build.`scaladoc-js-markdown` +val `scaladoc-js-contributors` = Build.`scaladoc-js-contributors` val `scala3-bench-run` = Build.`scala3-bench-run` val dist = Build.dist val `community-build` = Build.`community-build` diff --git a/docs/_layouts/blog-page.html b/docs/_layouts/blog-page.html index 6baad3d40ed8..c5d0fe8875e7 100644 --- a/docs/_layouts/blog-page.html +++ b/docs/_layouts/blog-page.html @@ -1,7 +1,7 @@ --- -layout: main +layout: static-site-main --- -
+

{{ page.title }}