diff --git a/compiler/src/dotty/tools/dotc/ast/Positioned.scala b/compiler/src/dotty/tools/dotc/ast/Positioned.scala index 835ce678bdb6..5f7c1e7ddc31 100644 --- a/compiler/src/dotty/tools/dotc/ast/Positioned.scala +++ b/compiler/src/dotty/tools/dotc/ast/Positioned.scala @@ -3,7 +3,7 @@ package dotc package ast import util.Spans._ -import util.{SourceFile, NoSource, SourcePosition, SrcPos} +import util.{SourceFile, NoSource, SourcePosition, SrcPos, Stats} import core.Contexts._ import core.Decorators._ import core.NameOps._ @@ -23,6 +23,8 @@ abstract class Positioned(implicit @constructorOnly src: SourceFile) extends Src private var myUniqueId: Int = _ private var mySpan: Span = _ + Stats.record(s"Positioned/$getClass") + /** A unique identifier. Among other things, used for determining the source file * component of the position. */ diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 471a1c988096..6ac54591c0a2 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -1248,53 +1248,68 @@ object Trees { */ protected def inlineContext(call: Tree)(using Context): Context = ctx - abstract class TreeMap(val cpy: TreeCopier = inst.cpy) { self => - def transform(tree: Tree)(using Context): Tree = { + abstract class TreeMap(val cpy: TreeCopier = inst.cpy): + self => + + def transform(tree: Tree)(using Context): Tree = + Stats.record(s"TreeMap.transform/$getClass") + def localCtx = + if (tree.hasType && tree.symbol.exists) ctx.withOwner(tree.symbol) else ctx + inContext( if tree.source != ctx.source && tree.source.exists then ctx.withSource(tree.source) else ctx ){ - Stats.record(s"TreeMap.transform/$getClass") - def localCtx = - if (tree.hasType && tree.symbol.exists) ctx.withOwner(tree.symbol) else ctx - - if (skipTransform(tree)) tree - else tree match { + if skipTransform(tree) then tree + else tree match case Ident(name) => tree + case Apply(fun, args) => + cpy.Apply(tree)(transform(fun), transform(args)) case Select(qualifier, name) => cpy.Select(tree)(transform(qualifier), name) - case This(qual) => + case TypeTree() => tree - case Super(qual, mix) => - cpy.Super(tree)(transform(qual), mix) - case Apply(fun, args) => - cpy.Apply(tree)(transform(fun), transform(args)) + case tree @ ValDef(name, tpt, _) => + if tree eq EmptyValDef then tree + else inContext(localCtx) { + val tpt1 = transform(tpt) + val rhs1 = transform(tree.rhs) + cpy.ValDef(tree)(name, tpt1, rhs1) + } + case Block(stats, expr) => + cpy.Block(tree)(transformStats(stats), transform(expr)) + case tree @ DefDef(name, tparams, vparamss, tpt, _) => + inContext(localCtx) { + cpy.DefDef(tree)(name, transformSub(tparams), vparamss mapConserve (transformSub(_)), transform(tpt), transform(tree.rhs)) + } + case If(cond, thenp, elsep) => + cpy.If(tree)(transform(cond), transform(thenp), transform(elsep)) case TypeApply(fun, args) => cpy.TypeApply(tree)(transform(fun), transform(args)) case Literal(const) => tree - case New(tpt) => - cpy.New(tree)(transform(tpt)) case Typed(expr, tpt) => cpy.Typed(tree)(transform(expr), transform(tpt)) - case NamedArg(name, arg) => - cpy.NamedArg(tree)(name, transform(arg)) - case Assign(lhs, rhs) => - cpy.Assign(tree)(transform(lhs), transform(rhs)) - case Block(stats, expr) => - cpy.Block(tree)(transformStats(stats), transform(expr)) - case If(cond, thenp, elsep) => - cpy.If(tree)(transform(cond), transform(thenp), transform(elsep)) + case tree @ TypeDef(name, rhs) => + inContext(localCtx) { + cpy.TypeDef(tree)(name, transform(rhs)) + } + case This(qual) => + tree case Closure(env, meth, tpt) => cpy.Closure(tree)(transform(env), transform(meth), transform(tpt)) case Match(selector, cases) => cpy.Match(tree)(transform(selector), transformSub(cases)) case CaseDef(pat, guard, body) => cpy.CaseDef(tree)(transform(pat), transform(guard), transform(body)) - case Labeled(bind, expr) => - cpy.Labeled(tree)(transformSub(bind), transform(expr)) + case New(tpt) => + cpy.New(tree)(transform(tpt)) + case NamedArg(name, arg) => + cpy.NamedArg(tree)(name, transform(arg)) + case Assign(lhs, rhs) => + cpy.Assign(tree)(transform(lhs), transform(rhs)) case Return(expr, from) => cpy.Return(tree)(transform(expr), transformSub(from)) case WhileDo(cond, body) => @@ -1305,8 +1320,24 @@ object Trees { cpy.SeqLiteral(tree)(transform(elems), transform(elemtpt)) case Inlined(call, bindings, expansion) => cpy.Inlined(tree)(call, transformSub(bindings), transform(expansion)(using inlineContext(call))) - case TypeTree() => - tree + case UnApply(fun, implicits, patterns) => + cpy.UnApply(tree)(transform(fun), transform(implicits), transform(patterns)) + case tree @ Template(constr, parents, self, _) if tree.derived.isEmpty => + cpy.Template(tree)(transformSub(constr), transform(tree.parents), Nil, transformSub(self), transformStats(tree.body)) + case Import(expr, selectors) => + cpy.Import(tree)(transform(expr), selectors) + case PackageDef(pid, stats) => + cpy.PackageDef(tree)(transformSub(pid), transformStats(stats)(using localCtx)) + case Annotated(arg, annot) => + cpy.Annotated(tree)(transform(arg), transform(annot)) + case Super(qual, mix) => + cpy.Super(tree)(transform(qual), mix) + case Bind(name, body) => + cpy.Bind(tree)(name, transform(body)) + case Labeled(bind, expr) => + cpy.Labeled(tree)(transformSub(bind), transform(expr)) + case Alternative(trees) => + cpy.Alternative(tree)(transform(trees)) case SingletonTypeTree(ref) => cpy.SingletonTypeTree(tree)(transform(ref)) case RefinedTypeTree(tpt, refinements) => @@ -1327,44 +1358,13 @@ object Trees { cpy.ByNameTypeTree(tree)(transform(result)) case TypeBoundsTree(lo, hi, alias) => cpy.TypeBoundsTree(tree)(transform(lo), transform(hi), transform(alias)) - case Bind(name, body) => - cpy.Bind(tree)(name, transform(body)) - case Alternative(trees) => - cpy.Alternative(tree)(transform(trees)) - case UnApply(fun, implicits, patterns) => - cpy.UnApply(tree)(transform(fun), transform(implicits), transform(patterns)) - case EmptyValDef => - tree - case tree @ ValDef(name, tpt, _) => - inContext(localCtx) { - val tpt1 = transform(tpt) - val rhs1 = transform(tree.rhs) - cpy.ValDef(tree)(name, tpt1, rhs1) - } - case tree @ DefDef(name, tparams, vparamss, tpt, _) => - inContext(localCtx) { - cpy.DefDef(tree)(name, transformSub(tparams), vparamss mapConserve (transformSub(_)), transform(tpt), transform(tree.rhs)) - } - case tree @ TypeDef(name, rhs) => - inContext(localCtx) { - cpy.TypeDef(tree)(name, transform(rhs)) - } - case tree @ Template(constr, parents, self, _) if tree.derived.isEmpty => - cpy.Template(tree)(transformSub(constr), transform(tree.parents), Nil, transformSub(self), transformStats(tree.body)) - case Import(expr, selectors) => - cpy.Import(tree)(transform(expr), selectors) - case PackageDef(pid, stats) => - cpy.PackageDef(tree)(transformSub(pid), transformStats(stats)(using localCtx)) - case Annotated(arg, annot) => - cpy.Annotated(tree)(transform(arg), transform(annot)) case Thicket(trees) => val trees1 = transform(trees) if (trees1 eq trees) tree else Thicket(trees1) case _ => transformMoreCases(tree) - } } - } + end transform def transformStats(trees: List[Tree])(using Context): List[Tree] = transform(trees) @@ -1379,7 +1379,7 @@ object Trees { assert(ctx.reporter.errorsReported) tree } - } + end TreeMap abstract class TreeAccumulator[X] { self => // Ties the knot of the traversal: call `foldOver(x, tree))` to dive in the `tree` node. @@ -1392,113 +1392,114 @@ object Trees { fold(x, trees) def foldOver(x: X, tree: Tree)(using Context): X = - if (tree.source != ctx.source && tree.source.exists) + + def localCtx = + if tree.hasType && tree.symbol.exists then ctx.withOwner(tree.symbol) else ctx + + Stats.record(s"TreeAccumulator.foldOver/$getClass") + + if tree.source != ctx.source && tree.source.exists then foldOver(x, tree)(using ctx.withSource(tree.source)) - else { - Stats.record(s"TreeAccumulator.foldOver/$getClass") - def localCtx = - if (tree.hasType && tree.symbol.exists) ctx.withOwner(tree.symbol) else ctx - tree match { - case Ident(name) => - x - case Select(qualifier, name) => - this(x, qualifier) - case This(qual) => - x - case Super(qual, mix) => - this(x, qual) - case Apply(fun, args) => - this(this(x, fun), args) - case TypeApply(fun, args) => - this(this(x, fun), args) - case Literal(const) => - x - case New(tpt) => - this(x, tpt) - case Typed(expr, tpt) => - this(this(x, expr), tpt) - case NamedArg(name, arg) => - this(x, arg) - case Assign(lhs, rhs) => - this(this(x, lhs), rhs) - case Block(stats, expr) => - this(this(x, stats), expr) - case If(cond, thenp, elsep) => - this(this(this(x, cond), thenp), elsep) - case Closure(env, meth, tpt) => - this(this(this(x, env), meth), tpt) - case Match(selector, cases) => - this(this(x, selector), cases) - case CaseDef(pat, guard, body) => - this(this(this(x, pat), guard), body) - case Labeled(bind, expr) => - this(this(x, bind), expr) - case Return(expr, from) => - this(this(x, expr), from) - case WhileDo(cond, body) => - this(this(x, cond), body) - case Try(block, handler, finalizer) => - this(this(this(x, block), handler), finalizer) - case SeqLiteral(elems, elemtpt) => - this(this(x, elems), elemtpt) - case Inlined(call, bindings, expansion) => - this(this(x, bindings), expansion)(using inlineContext(call)) - case TypeTree() => - x - case SingletonTypeTree(ref) => - this(x, ref) - case RefinedTypeTree(tpt, refinements) => - this(this(x, tpt), refinements) - case AppliedTypeTree(tpt, args) => - this(this(x, tpt), args) - case LambdaTypeTree(tparams, body) => - inContext(localCtx) { - this(this(x, tparams), body) - } - case TermLambdaTypeTree(params, body) => - inContext(localCtx) { - this(this(x, params), body) - } - case MatchTypeTree(bound, selector, cases) => - this(this(this(x, bound), selector), cases) - case ByNameTypeTree(result) => - this(x, result) - case TypeBoundsTree(lo, hi, alias) => - this(this(this(x, lo), hi), alias) - case Bind(name, body) => - this(x, body) - case Alternative(trees) => - this(x, trees) - case UnApply(fun, implicits, patterns) => - this(this(this(x, fun), implicits), patterns) - case tree @ ValDef(_, tpt, _) => - inContext(localCtx) { - this(this(x, tpt), tree.rhs) - } - case tree @ DefDef(_, tparams, vparamss, tpt, _) => - inContext(localCtx) { - this(this(vparamss.foldLeft(this(x, tparams))(apply), tpt), tree.rhs) - } - case TypeDef(_, rhs) => - inContext(localCtx) { - this(x, rhs) - } - case tree @ Template(constr, parents, self, _) if tree.derived.isEmpty => - this(this(this(this(x, constr), parents), self), tree.body) - case Import(expr, _) => - this(x, expr) - case PackageDef(pid, stats) => - this(this(x, pid), stats)(using localCtx) - case Annotated(arg, annot) => - this(this(x, arg), annot) - case Thicket(ts) => - this(x, ts) - case Hole(_, _, args) => - this(x, args) - case _ => - foldMoreCases(x, tree) - } - } + else tree match + case Ident(name) => + x + case Apply(fun, args) => + this(this(x, fun), args) + case Select(qualifier, name) => + this(x, qualifier) + case TypeTree() => + x + case tree @ ValDef(_, tpt, _) => + inContext(localCtx) { + this(this(x, tpt), tree.rhs) + } + case Block(stats, expr) => + this(this(x, stats), expr) + case tree @ DefDef(_, tparams, vparamss, tpt, _) => + inContext(localCtx) { + this(this(vparamss.foldLeft(this(x, tparams))(apply), tpt), tree.rhs) + } + case If(cond, thenp, elsep) => + this(this(this(x, cond), thenp), elsep) + case TypeApply(fun, args) => + this(this(x, fun), args) + case Literal(const) => + x + case Typed(expr, tpt) => + this(this(x, expr), tpt) + case TypeDef(_, rhs) => + inContext(localCtx) { + this(x, rhs) + } + case This(qual) => + x + case Closure(env, meth, tpt) => + this(this(this(x, env), meth), tpt) + case Match(selector, cases) => + this(this(x, selector), cases) + case CaseDef(pat, guard, body) => + this(this(this(x, pat), guard), body) + case New(tpt) => + this(x, tpt) + case NamedArg(name, arg) => + this(x, arg) + case Assign(lhs, rhs) => + this(this(x, lhs), rhs) + case Return(expr, from) => + this(this(x, expr), from) + case WhileDo(cond, body) => + this(this(x, cond), body) + case Try(block, handler, finalizer) => + this(this(this(x, block), handler), finalizer) + case SeqLiteral(elems, elemtpt) => + this(this(x, elems), elemtpt) + case Inlined(call, bindings, expansion) => + this(this(x, bindings), expansion)(using inlineContext(call)) + case UnApply(fun, implicits, patterns) => + this(this(this(x, fun), implicits), patterns) + case tree @ Template(constr, parents, self, _) if tree.derived.isEmpty => + this(this(this(this(x, constr), parents), self), tree.body) + case Import(expr, _) => + this(x, expr) + case PackageDef(pid, stats) => + this(this(x, pid), stats)(using localCtx) + case Annotated(arg, annot) => + this(this(x, arg), annot) + case Super(qual, mix) => + this(x, qual) + case Bind(name, body) => + this(x, body) + case Labeled(bind, expr) => + this(this(x, bind), expr) + case Alternative(trees) => + this(x, trees) + case SingletonTypeTree(ref) => + this(x, ref) + case RefinedTypeTree(tpt, refinements) => + this(this(x, tpt), refinements) + case AppliedTypeTree(tpt, args) => + this(this(x, tpt), args) + case LambdaTypeTree(tparams, body) => + inContext(localCtx) { + this(this(x, tparams), body) + } + case TermLambdaTypeTree(params, body) => + inContext(localCtx) { + this(this(x, params), body) + } + case MatchTypeTree(bound, selector, cases) => + this(this(this(x, bound), selector), cases) + case ByNameTypeTree(result) => + this(x, result) + case TypeBoundsTree(lo, hi, alias) => + this(this(this(x, lo), hi), alias) + case Thicket(ts) => + this(x, ts) + case Hole(_, _, args) => + this(x, args) + case _ => + foldMoreCases(x, tree) + end foldOver def foldMoreCases(x: X, tree: Tree)(using Context): X = { assert(ctx.reporter.errorsReported || ctx.mode.is(Mode.Interactive), tree) diff --git a/compiler/src/dotty/tools/dotc/config/Feature.scala b/compiler/src/dotty/tools/dotc/config/Feature.scala index 056f2703becb..a02a9e8c6d0a 100644 --- a/compiler/src/dotty/tools/dotc/config/Feature.scala +++ b/compiler/src/dotty/tools/dotc/config/Feature.scala @@ -23,8 +23,8 @@ object Feature: def toPrefix(sym: Symbol): String = if !sym.exists || sym == defn.LanguageModule.moduleClass then "" else toPrefix(sym.owner) + sym.name.stripModuleClassSuffix + "." - val prefix = if owner ne NoSymbol then toPrefix(owner) else "" - ctx.base.settings.language.value.contains(prefix + feature) + val fullName = if owner ne NoSymbol then toPrefix(owner) + feature else feature.toString + ctx.base.settings.language.value.contains(fullName) /** Is `feature` enabled by by an import? This is the case if the feature * is imported by a named import diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 2c3f88c1ce5c..b1d2addfe6af 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -181,6 +181,7 @@ class ScalaSettings extends Settings.SettingGroup { val YnoDecodeStacktraces: Setting[Boolean] = BooleanSetting("-Yno-decode-stacktraces", "Show raw StackOverflow stacktraces, instead of decoding them into triggering operations.") val Yinstrument: Setting[Boolean] = BooleanSetting("-Yinstrument", "Add instrumentation code that counts allocations and closure creations.") + val YinstrumentDefs: Setting[Boolean] = BooleanSetting("-Yinstrument-defs", "Add instrumentation code that counts method calls; needs -Yinstrument to be set, too.") /** Dottydoc specific settings */ val siteRoot: Setting[String] = StringSetting( diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 3732968aa884..cc44ec6fa6c2 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -211,7 +211,9 @@ class TypeApplications(val self: Type) extends AnyVal { */ def hkResult(using Context): Type = self.dealias match { case self: TypeRef => - if (self.symbol == defn.AnyKindClass) self else self.info.hkResult + if self.symbol.isClass then + if self.symbol == defn.AnyKindClass then self else NoType + else self.info.hkResult case self: AppliedType => if (self.tycon.typeSymbol.isClass) NoType else self.superType.hkResult case self: HKTypeLambda => self.resultType diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 575f58e273bf..a4fb267058aa 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -371,290 +371,274 @@ class TreePickler(pickler: TastyPickler) { stats.foreach(stat => if (!stat.isEmpty) pickleTree(stat)) } - def pickleTree(tree: Tree)(using Context): Unit = { + def pickleTree(tree: Tree)(using Context): Unit = val addr = registerTreeAddr(tree) - if (addr != currentAddr) { + if addr != currentAddr then writeByte(SHAREDterm) writeRef(addr) - } - else - try tree match { - case Ident(name) => - tree.tpe match { - case tp: TermRef if name != nme.WILDCARD => - // wildcards are pattern bound, need to be preserved as ids. - pickleType(tp) - case tp => - writeByte(if (tree.isType) IDENTtpt else IDENT) - pickleName(name) - pickleType(tp) - } - case This(qual) => - if (qual.isEmpty) pickleType(tree.tpe) - else { - writeByte(QUALTHIS) - val ThisType(tref) = tree.tpe - pickleTree(qual.withType(tref)) - } - case Select(qual, name) => - name match { - case OuterSelectName(_, levels) => - writeByte(SELECTouter) - withLength { - writeNat(levels) - pickleTree(qual) - val SkolemType(tp) = tree.tpe - pickleType(tp) - } - case _ => - val sig = tree.tpe.signature - val isAmbiguous = - sig != Signature.NotAMethod - && qual.tpe.nonPrivateMember(name).match - case d: MultiDenotation => d.atSignature(sig).isInstanceOf[MultiDenotation] - case _ => false - if isAmbiguous then - writeByte(SELECTin) - withLength { - pickleNameAndSig(name, tree.symbol.signature) - pickleTree(qual) - pickleType(tree.symbol.owner.typeRef) - } - else - writeByte(if (name.isTypeName) SELECTtpt else SELECT) - pickleNameAndSig(name, sig) - pickleTree(qual) - } - case Apply(fun, args) => - if (fun.symbol eq defn.throwMethod) { - writeByte(THROW) - pickleTree(args.head) - } - else { - writeByte(APPLY) - withLength { - pickleTree(fun) - args.foreach(pickleTree) - } - } - case TypeApply(fun, args) => - writeByte(TYPEAPPLY) + else try tree match + case Ident(name) => + def pickleIdent() = tree.tpe match + case tp: TermRef if name != nme.WILDCARD => + // wildcards are pattern bound, need to be preserved as ids. + pickleType(tp) + case tp => + writeByte(if (tree.isType) IDENTtpt else IDENT) + pickleName(name) + pickleType(tp) + pickleIdent() + case Apply(fun, args) => + if fun.symbol eq defn.throwMethod then + writeByte(THROW) + pickleTree(args.head) + else + writeByte(APPLY) withLength { pickleTree(fun) - args.foreach(pickleTpt) - } - case Literal(const1) => - pickleConstant { - tree.tpe match { - case ConstantType(const2) => const2 - case _ => const1 - } - } - case Super(qual, mix) => - writeByte(SUPER) - withLength { - pickleTree(qual); - if (!mix.isEmpty) { - val SuperType(_, mixinType: TypeRef) = tree.tpe - pickleTree(mix.withType(mixinType)) - } - } - case New(tpt) => - writeByte(NEW) - pickleTpt(tpt) - case Typed(expr, tpt) => - writeByte(TYPED) - withLength { pickleTree(expr); pickleTpt(tpt) } - case NamedArg(name, arg) => - writeByte(NAMEDARG) - pickleName(name) - pickleTree(arg) - case Assign(lhs, rhs) => - writeByte(ASSIGN) - withLength { pickleTree(lhs); pickleTree(rhs) } - case Block(stats, expr) => - writeByte(BLOCK) - stats.foreach(preRegister) - withLength { pickleTree(expr); stats.foreach(pickleTree) } - case tree @ If(cond, thenp, elsep) => - writeByte(IF) - withLength { - if (tree.isInline) writeByte(INLINE) - pickleTree(cond) - pickleTree(thenp) - pickleTree(elsep) - } - case Closure(env, meth, tpt) => - writeByte(LAMBDA) - assert(env.isEmpty) - withLength { - pickleTree(meth) - if (tpt.tpe.exists) pickleTpt(tpt) - } - case tree @ Match(selector, cases) => - writeByte(MATCH) - withLength { - if (tree.isInline) - if (selector.isEmpty) writeByte(IMPLICIT) - else { writeByte(INLINE); pickleTree(selector) } - else pickleTree(selector) - tree.cases.foreach(pickleTree) - } - case CaseDef(pat, guard, rhs) => - writeByte(CASEDEF) - withLength { pickleTree(pat); pickleTree(rhs); pickleTreeUnlessEmpty(guard) } - case Return(expr, from) => - writeByte(RETURN) - withLength { pickleSymRef(from.symbol); pickleTreeUnlessEmpty(expr) } - case WhileDo(cond, body) => - writeByte(WHILE) - withLength { pickleTree(cond); pickleTree(body) } - case Try(block, cases, finalizer) => - writeByte(TRY) - withLength { pickleTree(block); cases.foreach(pickleTree); pickleTreeUnlessEmpty(finalizer) } - case SeqLiteral(elems, elemtpt) => - writeByte(REPEATED) - withLength { pickleTree(elemtpt); elems.foreach(pickleTree) } - case Inlined(call, bindings, expansion) => - writeByte(INLINED) - bindings.foreach(preRegister) - withLength { - pickleTree(expansion) - if (!call.isEmpty) pickleTree(call) - bindings.foreach { b => - assert(b.isInstanceOf[DefDef] || b.isInstanceOf[ValDef]) - pickleTree(b) - } - } - case Bind(name, body) => - registerDef(tree.symbol) - writeByte(BIND) - withLength { - pickleName(name); pickleType(tree.symbol.info); pickleTree(body) + args.foreach(pickleTree) } - case Alternative(alts) => - writeByte(ALTERNATIVE) - withLength { alts.foreach(pickleTree) } - case UnApply(fun, implicits, patterns) => - writeByte(UNAPPLY) - withLength { - pickleTree(fun) - for (implicitArg <- implicits) { - writeByte(IMPLICITarg) - pickleTree(implicitArg) + case Select(qual, name) => + def pickleSelect() = name match + case OuterSelectName(_, levels) => + writeByte(SELECTouter) + withLength { + writeNat(levels) + pickleTree(qual) + val SkolemType(tp) = tree.tpe + pickleType(tp) } - pickleType(tree.tpe) - patterns.foreach(pickleTree) - } - case tree: ValDef => - pickleDef(VALDEF, tree, tree.tpt, tree.rhs) - case tree: DefDef => - def pickleParamss(paramss: List[List[ValDef]]): Unit = paramss match - case Nil => - case params :: rest => - pickleParams(params) - if params.isEmpty || rest.nonEmpty then writeByte(PARAMEND) - pickleParamss(rest) - def pickleAllParams = - pickleParams(tree.tparams) - pickleParamss(tree.vparamss) - pickleDef(DEFDEF, tree, tree.tpt, tree.rhs, pickleAllParams) - case tree: TypeDef => - pickleDef(TYPEDEF, tree, tree.rhs) - case tree: Template => - registerDef(tree.symbol) - writeByte(TEMPLATE) - val (params, rest) = decomposeTemplateBody(tree.body) - withLength { + case _ => + val sig = tree.tpe.signature + val isAmbiguous = + sig != Signature.NotAMethod + && qual.tpe.nonPrivateMember(name).match + case d: MultiDenotation => d.atSignature(sig).isInstanceOf[MultiDenotation] + case _ => false + if isAmbiguous then + writeByte(SELECTin) + withLength { + pickleNameAndSig(name, tree.symbol.signature) + pickleTree(qual) + pickleType(tree.symbol.owner.typeRef) + } + else + writeByte(if (name.isTypeName) SELECTtpt else SELECT) + pickleNameAndSig(name, sig) + pickleTree(qual) + pickleSelect() + case tree: TypeTree => + pickleType(tree.tpe) + case tree: ValDef => + pickleDef(VALDEF, tree, tree.tpt, tree.rhs) + case Block(stats, expr) => + writeByte(BLOCK) + stats.foreach(preRegister) + withLength { pickleTree(expr); stats.foreach(pickleTree) } + case tree: DefDef => + def pickleParamss(paramss: List[List[ValDef]]): Unit = paramss match + case Nil => + case params :: rest => pickleParams(params) - tree.parents.foreach(pickleTree) - val cinfo @ ClassInfo(_, _, _, _, selfInfo) = tree.symbol.owner.info - if (!tree.self.isEmpty) { - writeByte(SELFDEF) - pickleName(tree.self.name) - - if (!tree.self.tpt.isEmpty) pickleTree(tree.self.tpt) - else { - if (!tree.self.isEmpty) registerTreeAddr(tree.self) - pickleType { - selfInfo match { - case sym: Symbol => sym.info - case tp: Type => tp - } - } + if params.isEmpty || rest.nonEmpty then writeByte(PARAMEND) + pickleParamss(rest) + def pickleAllParams = + pickleParams(tree.tparams) + pickleParamss(tree.vparamss) + pickleDef(DEFDEF, tree, tree.tpt, tree.rhs, pickleAllParams) + case tree @ If(cond, thenp, elsep) => + writeByte(IF) + withLength { + if tree.isInline then writeByte(INLINE) + pickleTree(cond) + pickleTree(thenp) + pickleTree(elsep) + } + case TypeApply(fun, args) => + writeByte(TYPEAPPLY) + withLength { + pickleTree(fun) + args.foreach(pickleTpt) + } + case Literal(const1) => + pickleConstant { + tree.tpe match + case ConstantType(const2) => const2 + case _ => const1 + } + case Typed(expr, tpt) => + writeByte(TYPED) + withLength { pickleTree(expr); pickleTpt(tpt) } + case tree: TypeDef => + pickleDef(TYPEDEF, tree, tree.rhs) + case This(qual) => + if qual.isEmpty then pickleType(tree.tpe) + else + writeByte(QUALTHIS) + val ThisType(tref) = tree.tpe + pickleTree(qual.withType(tref)) + case New(tpt) => + writeByte(NEW) + pickleTpt(tpt) + case Closure(env, meth, tpt) => + writeByte(LAMBDA) + assert(env.isEmpty) + withLength { + pickleTree(meth) + if tpt.tpe.exists then pickleTpt(tpt) + } + case tree @ Match(selector, cases) => + writeByte(MATCH) + withLength { + if tree.isInline then + if selector.isEmpty then writeByte(IMPLICIT) + else { writeByte(INLINE); pickleTree(selector) } + else pickleTree(selector) + tree.cases.foreach(pickleTree) + } + case CaseDef(pat, guard, rhs) => + writeByte(CASEDEF) + withLength { pickleTree(pat); pickleTree(rhs); pickleTreeUnlessEmpty(guard) } + case NamedArg(name, arg) => + writeByte(NAMEDARG) + pickleName(name) + pickleTree(arg) + case Assign(lhs, rhs) => + writeByte(ASSIGN) + withLength { pickleTree(lhs); pickleTree(rhs) } + case Return(expr, from) => + writeByte(RETURN) + withLength { pickleSymRef(from.symbol); pickleTreeUnlessEmpty(expr) } + case WhileDo(cond, body) => + writeByte(WHILE) + withLength { pickleTree(cond); pickleTree(body) } + case Try(block, cases, finalizer) => + writeByte(TRY) + withLength { pickleTree(block); cases.foreach(pickleTree); pickleTreeUnlessEmpty(finalizer) } + case SeqLiteral(elems, elemtpt) => + writeByte(REPEATED) + withLength { pickleTree(elemtpt); elems.foreach(pickleTree) } + case Inlined(call, bindings, expansion) => + writeByte(INLINED) + bindings.foreach(preRegister) + withLength { + pickleTree(expansion) + if !call.isEmpty then pickleTree(call) + for b <- bindings do + assert(b.isInstanceOf[DefDef] || b.isInstanceOf[ValDef]) + pickleTree(b) + } + case tree: Template => + registerDef(tree.symbol) + writeByte(TEMPLATE) + val (params, rest) = decomposeTemplateBody(tree.body) + withLength { + pickleParams(params) + tree.parents.foreach(pickleTree) + val cinfo @ ClassInfo(_, _, _, _, selfInfo) = tree.symbol.owner.info + if !tree.self.isEmpty then + writeByte(SELFDEF) + pickleName(tree.self.name) + if !tree.self.tpt.isEmpty then pickleTree(tree.self.tpt) + else + if !tree.self.isEmpty then registerTreeAddr(tree.self) + pickleType { + selfInfo match + case sym: Symbol => sym.info + case tp: Type => tp } - } - pickleStats(tree.constr :: rest) - } - case Import(expr, selectors) => - writeByte(IMPORT) - withLength { - pickleTree(expr) - pickleSelectors(selectors) - } - case PackageDef(pid, stats) => - writeByte(PACKAGE) - withLength { pickleType(pid.tpe); pickleStats(stats) } - case tree: TypeTree => + pickleStats(tree.constr :: rest) + } + case Import(expr, selectors) => + writeByte(IMPORT) + withLength { + pickleTree(expr) + pickleSelectors(selectors) + } + case Super(qual, mix) => + writeByte(SUPER) + withLength { + pickleTree(qual) + if !mix.isEmpty then + val SuperType(_, mixinType: TypeRef) = tree.tpe + pickleTree(mix.withType(mixinType)) + } + case PackageDef(pid, stats) => + writeByte(PACKAGE) + withLength { pickleType(pid.tpe); pickleStats(stats) } + case Bind(name, body) => + registerDef(tree.symbol) + writeByte(BIND) + withLength { + pickleName(name); pickleType(tree.symbol.info); pickleTree(body) + } + case Alternative(alts) => + writeByte(ALTERNATIVE) + withLength { alts.foreach(pickleTree) } + case UnApply(fun, implicits, patterns) => + writeByte(UNAPPLY) + withLength { + pickleTree(fun) + for implicitArg <- implicits do + writeByte(IMPLICITarg) + pickleTree(implicitArg) pickleType(tree.tpe) - case SingletonTypeTree(ref) => - writeByte(SINGLETONtpt) - pickleTree(ref) - case RefinedTypeTree(parent, refinements) => - if (refinements.isEmpty) pickleTree(parent) - else { - val refineCls = refinements.head.symbol.owner.asClass - registerDef(refineCls) - pickledTypes(refineCls.typeRef) = currentAddr - writeByte(REFINEDtpt) - refinements.foreach(preRegister) - withLength { pickleTree(parent); refinements.foreach(pickleTree) } - } - case AppliedTypeTree(tycon, args) => - writeByte(APPLIEDtpt) - withLength { pickleTree(tycon); args.foreach(pickleTree) } - case MatchTypeTree(bound, selector, cases) => - writeByte(MATCHtpt) - withLength { - if (!bound.isEmpty) pickleTree(bound) - pickleTree(selector) - cases.foreach(pickleTree) - } - case ByNameTypeTree(tp) => - writeByte(BYNAMEtpt) - pickleTree(tp) - case Annotated(tree, annot) => - writeByte(ANNOTATEDtpt) - withLength { pickleTree(tree); pickleTree(annot) } - case LambdaTypeTree(tparams, body) => - writeByte(LAMBDAtpt) - withLength { pickleParams(tparams); pickleTree(body) } - case TypeBoundsTree(lo, hi, alias) => - writeByte(TYPEBOUNDStpt) - withLength { - pickleTree(lo); - if alias.isEmpty then - if hi ne lo then pickleTree(hi) - else - pickleTree(hi) - pickleTree(alias) - } - case Hole(_, idx, args) => - writeByte(HOLE) - withLength { - writeNat(idx) - pickleType(tree.tpe, richTypes = true) - args.foreach(pickleTree) - } - } - catch { - case ex: TypeError => - report.error(ex.toMessage, tree.srcPos.focus) - case ex: AssertionError => - println(i"error when pickling tree $tree") - throw ex - } - } + patterns.foreach(pickleTree) + } + case SingletonTypeTree(ref) => + writeByte(SINGLETONtpt) + pickleTree(ref) + case RefinedTypeTree(parent, refinements) => + if refinements.isEmpty then pickleTree(parent) + else + val refineCls = refinements.head.symbol.owner.asClass + registerDef(refineCls) + pickledTypes(refineCls.typeRef) = currentAddr + writeByte(REFINEDtpt) + refinements.foreach(preRegister) + withLength { pickleTree(parent); refinements.foreach(pickleTree) } + case AppliedTypeTree(tycon, args) => + writeByte(APPLIEDtpt) + withLength { pickleTree(tycon); args.foreach(pickleTree) } + case MatchTypeTree(bound, selector, cases) => + writeByte(MATCHtpt) + withLength { + if (!bound.isEmpty) pickleTree(bound) + pickleTree(selector) + cases.foreach(pickleTree) + } + case ByNameTypeTree(tp) => + writeByte(BYNAMEtpt) + pickleTree(tp) + case Annotated(tree, annot) => + writeByte(ANNOTATEDtpt) + withLength { pickleTree(tree); pickleTree(annot) } + case LambdaTypeTree(tparams, body) => + writeByte(LAMBDAtpt) + withLength { pickleParams(tparams); pickleTree(body) } + case TypeBoundsTree(lo, hi, alias) => + writeByte(TYPEBOUNDStpt) + withLength { + pickleTree(lo); + if alias.isEmpty then + if hi ne lo then pickleTree(hi) + else + pickleTree(hi) + pickleTree(alias) + } + case Hole(_, idx, args) => + writeByte(HOLE) + withLength { + writeNat(idx) + pickleType(tree.tpe, richTypes = true) + args.foreach(pickleTree) + } + catch + case ex: TypeError => + report.error(ex.toMessage, tree.srcPos.focus) + case ex: AssertionError => + println(i"error when pickling tree $tree") + throw ex + end pickleTree def pickleSelectors(selectors: List[untpd.ImportSelector])(using Context): Unit = for sel <- selectors do diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index 241319ea6ff7..bdf74623b244 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -565,7 +565,7 @@ object Scanners { lastOffset = prev.lastOffset lineOffset = prev.lineOffset } - token match { + (token: @switch) match { case CASE => lookAhead() if (token == CLASS) fuse(CASECLASS) @@ -601,8 +601,8 @@ object Scanners { if colonSyntax then observeColonEOL() case RBRACE | RPAREN | RBRACKET => closeIndented() - case EOF if !source.maybeIncomplete => - closeIndented() + case EOF => + if !source.maybeIncomplete then closeIndented() case _ => } } diff --git a/compiler/src/dotty/tools/dotc/transform/Instrumentation.scala b/compiler/src/dotty/tools/dotc/transform/Instrumentation.scala index b4d2c541f2c5..676cf00e2f46 100644 --- a/compiler/src/dotty/tools/dotc/transform/Instrumentation.scala +++ b/compiler/src/dotty/tools/dotc/transform/Instrumentation.scala @@ -74,6 +74,21 @@ class Instrumentation extends MiniPhase { thisPhase => private def ok(using Context) = !ctx.owner.ownersIterator.exists(_.name.toString.startsWith("Stats")) + override def transformDefDef(tree: DefDef)(using Context): Tree = + val sym = tree.symbol + if ctx.settings.YinstrumentDefs.value + && ok + && sym.exists + && !sym.isOneOf(Synthetic | Artifact) + then + def icall = record(i"method/${sym.fullName}", tree) + def rhs1 = tree.rhs match + case rhs @ Block(stats, expr) => cpy.Block(rhs)(icall :: stats, expr) + case _: Match | _: If | _: Try | _: Labeled => cpy.Block(tree.rhs)(icall :: Nil, tree.rhs) + case rhs => rhs + cpy.DefDef(tree)(rhs = rhs1) + else tree + override def transformApply(tree: Apply)(using Context): Tree = tree.fun match { case Select(nu: New, _) => cpy.Block(tree)(record(i"alloc/${nu.tpe}", tree) :: Nil, tree) diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 5ed99adaff37..f89a698f586c 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -231,12 +231,37 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase } override def transform(tree: Tree)(using Context): Tree = - try tree match { + try tree match case tree: Ident if !tree.isType => tree.tpe match { case tpe: ThisType => This(tpe.cls).withSpan(tree.span) case _ => tree } + case tree: Apply => + def transformApply() = + val methType = tree.fun.tpe.widen + val app = + if (methType.isErasedMethod) + tpd.cpy.Apply(tree)( + tree.fun, + tree.args.mapConserve(arg => + if (methType.isImplicitMethod && arg.span.isSynthetic) ref(defn.Predef_undefined) + else dropInlines.transform(arg))) + else tree + def app1 = + // reverse order of transforming args and fun. This way, we get a chance to see other + // well-formedness errors before reporting errors in possible inferred type args of fun. + val args1 = transform(app.args) + cpy.Apply(app)(transform(app.fun), args1) + methPart(app) match + case Select(nu: New, nme.CONSTRUCTOR) if isCheckable(nu) => + // need to check instantiability here, because the type of the New itself + // might be a type constructor. + Checking.checkInstantiable(tree.tpe, nu.srcPos) + withNoCheckNews(nu :: Nil)(app1) + case _ => + app1 + transformApply() case tree @ Select(qual, name) => if (name.isTypeName) { Checking.checkRealizable(qual.tpe, qual.srcPos) @@ -244,61 +269,13 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase } else transformSelect(tree, Nil) - case tree: Apply => - val methType = tree.fun.tpe.widen - val app = - if (methType.isErasedMethod) - tpd.cpy.Apply(tree)( - tree.fun, - tree.args.mapConserve(arg => - if (methType.isImplicitMethod && arg.span.isSynthetic) ref(defn.Predef_undefined) - else dropInlines.transform(arg))) - else - tree - def app1 = - // reverse order of transforming args and fun. This way, we get a chance to see other - // well-formedness errors before reporting errors in possible inferred type args of fun. - val args1 = transform(app.args) - cpy.Apply(app)(transform(app.fun), args1) - methPart(app) match - case Select(nu: New, nme.CONSTRUCTOR) if isCheckable(nu) => - // need to check instantiability here, because the type of the New itself - // might be a type constructor. - Checking.checkInstantiable(tree.tpe, nu.srcPos) - withNoCheckNews(nu :: Nil)(app1) - case _ => - app1 - case UnApply(fun, implicits, patterns) => - // Reverse transform order for the same reason as in `app1` above. - val patterns1 = transform(patterns) - cpy.UnApply(tree)(transform(fun), transform(implicits), patterns1) - case tree: TypeApply => - if tree.symbol.isQuote then - ctx.compilationUnit.needsStaging = true - val tree1 @ TypeApply(fn, args) = normalizeTypeArgs(tree) - args.foreach(checkInferredWellFormed) - if (fn.symbol != defn.ChildAnnot.primaryConstructor) - // Make an exception for ChildAnnot, which should really have AnyKind bounds - Checking.checkBounds(args, fn.tpe.widen.asInstanceOf[PolyType]) - fn match { - case sel: Select => - val args1 = transform(args) - val sel1 = transformSelect(sel, args1) - cpy.TypeApply(tree1)(sel1, args1) - case _ => - super.transform(tree1) - } - case Inlined(call, bindings, expansion) if !call.isEmpty => - val pos = call.sourcePos - val callTrace = Inliner.inlineCallTrace(call.symbol, pos)(using ctx.withSource(pos.source)) - cpy.Inlined(tree)(callTrace, transformSub(bindings), transform(expansion)(using inlineContext(call))) - case templ: Template => - withNoCheckNews(templ.parents.flatMap(newPart)) { - forwardParamAccessors(templ) - synthMbr.addSyntheticMembers( - superAcc.wrapTemplate(templ)( - super.transform(_).asInstanceOf[Template])) - } + case tree: TypeTree => + tree.withType( + tree.tpe match { + case AnnotatedType(tpe, annot) => AnnotatedType(tpe, transformAnnot(annot)) + case tpe => tpe + } + ) case tree: ValDef => val tree1 = cpy.ValDef(tree)(rhs = normalizeErasedRhs(tree.rhs, tree.symbol)) processValOrDefDef(super.transform(tree1)) @@ -307,20 +284,58 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase val tree1 = cpy.DefDef(tree)(rhs = normalizeErasedRhs(tree.rhs, tree.symbol)) processValOrDefDef(superAcc.wrapDefDef(tree1)(super.transform(tree1).asInstanceOf[DefDef])) case tree: TypeDef => - val sym = tree.symbol - if (sym.isClass) - VarianceChecker.check(tree) - // Add SourceFile annotation to top-level classes - if sym.owner.is(Package) - && ctx.compilationUnit.source.exists - && sym != defn.SourceFileAnnot - then - sym.addAnnotation(Annotation.makeSourceFile(ctx.compilationUnit.source.file.path)) - else (tree.rhs, sym.info) match - case (rhs: LambdaTypeTree, bounds: TypeBounds) => - VarianceChecker.checkLambda(rhs, bounds) - case _ => + def checkTypeDef() = + val sym = tree.symbol + if sym.isClass then + VarianceChecker.check(tree) + // Add SourceFile annotation to top-level classes + if sym.owner.is(Package) + && ctx.compilationUnit.source.exists + && sym != defn.SourceFileAnnot + then + sym.addAnnotation(Annotation.makeSourceFile(ctx.compilationUnit.source.file.path)) + else (tree.rhs, sym.info) match + case (rhs: LambdaTypeTree, bounds: TypeBounds) => + VarianceChecker.checkLambda(rhs, bounds) + case _ => + checkTypeDef() processMemberDef(super.transform(tree)) + case tree: TypeApply => + def transformTypeApply() = + if tree.symbol.isQuote then + ctx.compilationUnit.needsStaging = true + val tree1 @ TypeApply(fn, args) = normalizeTypeArgs(tree) + args.foreach(checkInferredWellFormed) + if fn.symbol != defn.ChildAnnot.primaryConstructor then + // Make an exception for ChildAnnot, which should really have AnyKind bounds + Checking.checkBounds(args, fn.tpe.widen.asInstanceOf[PolyType]) + fn match + case sel: Select => + val args1 = transform(args) + val sel1 = transformSelect(sel, args1) + cpy.TypeApply(tree1)(sel1, args1) + case _ => + super.transform(tree1) + transformTypeApply() + case UnApply(fun, implicits, patterns) => + // Reverse transform order for the same reason as in `app1` above. + val patterns1 = transform(patterns) + cpy.UnApply(tree)(transform(fun), transform(implicits), patterns1) + case Inlined(call, bindings, expansion) if !call.isEmpty => + def transformInlined() = + val pos = call.sourcePos + val callTrace = Inliner.inlineCallTrace(call.symbol, pos)(using ctx.withSource(pos.source)) + cpy.Inlined(tree)(callTrace, transformSub(bindings), transform(expansion)(using inlineContext(call))) + transformInlined() + case templ: Template => + def transformTemplate() = + withNoCheckNews(templ.parents.flatMap(newPart)) { + forwardParamAccessors(templ) + synthMbr.addSyntheticMembers( + superAcc.wrapTemplate(templ)( + super.transform(_).asInstanceOf[Template])) + } + transformTemplate() case tree: New if isCheckable(tree) => Checking.checkInstantiable(tree.tpe, tree.srcPos) super.transform(tree) @@ -330,40 +345,39 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase case tree @ Annotated(annotated, annot) => cpy.Annotated(tree)(transform(annotated), transformAnnot(annot)) case tree: AppliedTypeTree => - if (tree.tpt.symbol == defn.andType) - Checking.checkNonCyclicInherited(tree.tpe, tree.args.tpes, EmptyScope, tree.srcPos) - // Ideally, this should be done by Typer, but we run into cyclic references - // when trying to typecheck self types which are intersections. - else if (tree.tpt.symbol == defn.orType) - () // nothing to do - else - Checking.checkAppliedType(tree) + def checkAppliedTypeTree() = + if (tree.tpt.symbol == defn.andType) + Checking.checkNonCyclicInherited(tree.tpe, tree.args.tpes, EmptyScope, tree.srcPos) + // Ideally, this should be done by Typer, but we run into cyclic references + // when trying to typecheck self types which are intersections. + else if (tree.tpt.symbol == defn.orType) + () // nothing to do + else + Checking.checkAppliedType(tree) + checkAppliedTypeTree() super.transform(tree) case SingletonTypeTree(ref) => Checking.checkRealizable(ref.tpe, ref.srcPos) super.transform(tree) - case tree: TypeTree => - tree.withType( - tree.tpe match { - case AnnotatedType(tpe, annot) => AnnotatedType(tpe, transformAnnot(annot)) - case tpe => tpe - } - ) case Import(expr, selectors) => - val exprTpe = expr.tpe - val seen = mutable.Set.empty[Name] + def checkImport() = + val exprTpe = expr.tpe + val seen = mutable.Set.empty[Name] - def checkIdent(sel: untpd.ImportSelector): Unit = - if !exprTpe.member(sel.name).exists - && !exprTpe.member(sel.name.toTypeName).exists - && !exprTpe.member(sel.name.toExtensionName).exists then - report.error(NotAMember(exprTpe, sel.name, "value"), sel.imported.srcPos) - if seen.contains(sel.name) then - report.error(ImportRenamedTwice(sel.imported), sel.imported.srcPos) - seen += sel.name + def checkIdent(sel: untpd.ImportSelector): Unit = + if !exprTpe.member(sel.name).exists + && !exprTpe.member(sel.name.toTypeName).exists + && !exprTpe.member(sel.name.toExtensionName).exists + then + report.error(NotAMember(exprTpe, sel.name, "value"), sel.imported.srcPos) + if seen.contains(sel.name) then + report.error(ImportRenamedTwice(sel.imported), sel.imported.srcPos) + seen += sel.name - for sel <- selectors do - if !sel.isWildcard then checkIdent(sel) + for sel <- selectors do + if !sel.isWildcard then checkIdent(sel) + end checkImport + checkImport() super.transform(tree) case Typed(Ident(nme.WILDCARD), _) => withMode(Mode.Pattern)(super.transform(tree)) @@ -375,22 +389,22 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase // (which translates to) // case x: (_: Tree[?]) case m @ MatchTypeTree(bounds, selector, cases) => - // Analog to the case above for match types - def tranformIgnoringBoundsCheck(x: CaseDef): CaseDef = - withMode(Mode.Pattern)(super.transform(x)).asInstanceOf[CaseDef] - cpy.MatchTypeTree(tree)( - super.transform(bounds), - super.transform(selector), - cases.mapConserve(tranformIgnoringBoundsCheck) - ) + def transformMatchTypeTree() = + // Analog to the case above for match types + def tranformIgnoringBoundsCheck(x: CaseDef): CaseDef = + withMode(Mode.Pattern)(super.transform(x)).asInstanceOf[CaseDef] + cpy.MatchTypeTree(tree)( + super.transform(bounds), + super.transform(selector), + cases.mapConserve(tranformIgnoringBoundsCheck) + ) + transformMatchTypeTree() case tree => super.transform(tree) - } - catch { - case ex : AssertionError => - println(i"error while transforming $tree") - throw ex - } + catch case ex : AssertionError => + println(i"error while transforming $tree") + throw ex + end transform /** Transforms the rhs tree into a its default tree if it is in an `erased` val/def. * Performed to shrink the tree that is known to be erased later. diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 9e9e8ba05ec4..89f8f334b030 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -2533,7 +2533,7 @@ class Typer extends Namer !tree.isInstanceOf[Applications.IntegratedTypeArgs]) // don't interpolate in the middle of an extension method application if (!tree.tpe.widen.isInstanceOf[MethodOrPoly] // wait with simplifying until method is fully applied - || tree.isDef) { // ... unless tree is a definition + || tree.isDef) { // ... unless tree is a definition interpolateTypeVars(tree, pt, locked) tree.overwriteType(tree.tpe.simplified) }