diff --git a/compiler/src/dotty/tools/dotc/CompilationUnit.scala b/compiler/src/dotty/tools/dotc/CompilationUnit.scala index 193baaf7a55b..d448aab9a8ad 100644 --- a/compiler/src/dotty/tools/dotc/CompilationUnit.scala +++ b/compiler/src/dotty/tools/dotc/CompilationUnit.scala @@ -57,6 +57,9 @@ class CompilationUnit protected (val source: SourceFile, val info: CompilationUn */ var needsInlining: Boolean = false + /** TODO */ + var needsTraitInlining: Boolean = false + var hasMacroAnnotations: Boolean = false /** Set to `true` if inliner added anonymous mirrors that need to be completed */ diff --git a/compiler/src/dotty/tools/dotc/Compiler.scala b/compiler/src/dotty/tools/dotc/Compiler.scala index ffd3d27f7c99..bc88a7046e11 100644 --- a/compiler/src/dotty/tools/dotc/Compiler.scala +++ b/compiler/src/dotty/tools/dotc/Compiler.scala @@ -48,6 +48,7 @@ class Compiler { protected def picklerPhases: List[List[Phase]] = List(new Pickler) :: // Generate TASTY info List(new sbt.ExtractAPI) :: // Sends a representation of the API of classes to sbt via callbacks + List(new TraitInlining) :: // Generate inline trait members List(new Inlining) :: // Inline and execute macros List(new PostInlining) :: // Add mirror support for inlined code List(new CheckUnused.PostInlining) :: // Check for unused elements @@ -66,6 +67,7 @@ class Compiler { new CookComments, // Cook the comments: expand variables, doc, etc. new CheckLoopingImplicits, // Check that implicit defs do not call themselves in an infinite loop new BetaReduce, // Reduce closure applications + new Devirtualize, // Devirtualize method calls new InlineVals, // Check right hand-sides of an `inline val`s new ExpandSAMs, // Expand single abstract method closures to anonymous classes new ElimRepeated, // Rewrite vararg parameters and arguments @@ -93,6 +95,7 @@ class Compiler { new StringInterpolatorOpt, // Optimizes raw and s and f string interpolators by rewriting them to string concatenations or formats new DropBreaks) :: // Optimize local Break throws by rewriting them List(new PruneErasedDefs, // Drop erased definitions from scopes and simplify erased expressions + new DeferInlineTraits, // Defer all members in inline traits new UninitializedDefs, // Replaces `compiletime.uninitialized` by `_` new InlinePatterns, // Remove placeholders of inlined patterns new VCInlineMethods, // Inlines calls to value class methods diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index 8110bc769d4f..12198cc1dd82 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -446,13 +446,13 @@ object Flags { /** Flags representing source modifiers */ private val CommonSourceModifierFlags: FlagSet = - commonFlags(Private, Protected, Final, Case, Implicit, Given, Override, JavaStatic, Transparent, Erased) + commonFlags(Private, Protected, Final, Case, Implicit, Given, Override, JavaStatic, Transparent, Erased, Inline) val TypeSourceModifierFlags: FlagSet = CommonSourceModifierFlags.toTypeFlags | Abstract | Sealed | Opaque | Open val TermSourceModifierFlags: FlagSet = - CommonSourceModifierFlags.toTermFlags | Inline | AbsOverride | Lazy + CommonSourceModifierFlags.toTermFlags | AbsOverride | Lazy /** Flags representing modifiers that can appear in trees */ val ModifierFlags: FlagSet = @@ -584,6 +584,7 @@ object Flags { val LazyGiven: FlagSet = Given | Lazy val InlineOrProxy: FlagSet = Inline | InlineProxy // An inline method or inline argument proxy */ val InlineMethod: FlagSet = Inline | Method + val InlineTrait: FlagSet = Inline | Trait val InlineImplicitMethod: FlagSet = Implicit | InlineMethod val InlineParam: FlagSet = Inline | Param val InlineByNameProxy: FlagSet = InlineProxy | Method diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index f01d2faf86c4..c02c038693e6 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1014,6 +1014,9 @@ object SymDenotations { def isInlineMethod(using Context): Boolean = isAllOf(InlineMethod, butNot = Accessor) + def isInlineTrait(using Context): Boolean = + isAllOf(InlineTrait) + /** Does this method or field need to be retained at runtime */ def isRetainedInline(using Context): Boolean = is(Inline, butNot = Deferred) diff --git a/compiler/src/dotty/tools/dotc/inlines/InlineTraits.scala b/compiler/src/dotty/tools/dotc/inlines/InlineTraits.scala new file mode 100644 index 000000000000..f1a9abea0f4b --- /dev/null +++ b/compiler/src/dotty/tools/dotc/inlines/InlineTraits.scala @@ -0,0 +1,195 @@ +package dotty.tools.dotc.inlines + +import dotty.tools.dotc.ast.tpd +import dotty.tools.dotc.ast.Trees.* +import dotty.tools.dotc.core.Constants.* +import dotty.tools.dotc.core.Contexts.* +import dotty.tools.dotc.core.Decorators.* +import dotty.tools.dotc.core.Flags.* +import dotty.tools.dotc.core.NameOps.* +import dotty.tools.dotc.core.Names.TypeName +import dotty.tools.dotc.core.Symbols.* +import dotty.tools.dotc.core.Types.* +import dotty.tools.dotc.core.Scopes.newScope +import dotty.tools.dotc.report +import dotty.tools.dotc.util.SrcPos +import dotty.tools.dotc.util.Spans.Span + +object InlineTraits: + import tpd.* + + def adaptNoInit(cls: ClassSymbol, parents1: List[Tree])(using Context): Unit = + if parents1.exists(parent => parent.symbol.isInlineTrait && !parent.symbol.is(NoInits)) then + cls.resetFlag(NoInits) + + def needsTraitInlining(cls: ClassSymbol)(using Context): Boolean = + !cls.isInlineTrait + && cls.info.parents.exists(parent => parent.typeSymbol.isInlineTrait) + + /** Generate all inlined definitions for all inline parents of `cls`. + * New definition symbol are not entered in the class `cls`. + */ + def inlinedMemberSymbols(cls: ClassSymbol)(using Context): List[Symbol] = + assert(!cls.isInlineTrait, cls) + for + denot <- cls.typeRef.allMembers.toList + sym = denot.symbol + if isInlinableMember(sym) + yield + val traitTargs = parentTargs(cls, sym) + if sym.isClass then inlinedSymbolClassDef(cls, sym.asClass, traitTargs) + else inlinedSymbolValOrDef(cls, sym, traitTargs) + end inlinedMemberSymbols + + def inlinedPrivateMemberSymbols(cls: ClassSymbol)(using Context): List[Symbol] = + assert(!cls.isInlineTrait, cls) + println(" ") + for + parent <- cls.info.parents + parentSym = parent.typeSymbol + if parentSym.isAllOf(InlineTrait) + sym <- parentSym.info.decls.toList + if sym.isTerm && sym.is(Private) + yield + val traitTargs = parentTargs(cls, sym) + inlinedSymbolPrivateValOrDef(cls, sym, traitTargs) + + + + private def isInlinableMember(sym: Symbol)(using Context): Boolean = + (sym.isTerm || sym.isClass) + && !sym.isConstructor && !sym.is(ParamAccessor) + && sym.owner.isInlineTrait + + private def parentTargs(cls: ClassSymbol, inlinableDecl: Symbol)(using Context): List[Type] = + val baseClass = inlinableDecl.owner.asClass + mixinParentTypeOf(cls, baseClass).baseType(baseClass) match + case AppliedType(_, targs) => targs + case _ => Nil + + private def inlinedSymbolValOrDef(cls: ClassSymbol, inlinableDecl: Symbol, traitTargs: List[Type])(using Context): Symbol = + val flags = inlinableDecl.flags | Override | Synthetic + val info = inlinableDecl.info + .substThis(inlinableDecl.owner.asClass, ThisType.raw(cls.typeRef)) + .subst(inlinableDecl.owner.typeParams, traitTargs) + val privateWithin = inlinableDecl.privateWithin // TODO what should `privateWithin` be? + newSymbol(cls, inlinableDecl.name, flags, info, privateWithin, cls.span) + + private def inlinedSymbolPrivateValOrDef(cls: ClassSymbol, inlinableDecl: Symbol, traitTargs: List[Type])(using Context): Symbol = + val name = atPhase(ctx.phase.next) { inlinableDecl.name } + val flags = inlinableDecl.flags | Synthetic + val info = inlinableDecl.info + .substThis(inlinableDecl.owner.asClass, ThisType.raw(cls.typeRef)) + .subst(inlinableDecl.owner.typeParams, traitTargs) + val privateWithin = inlinableDecl.privateWithin // TODO what should `privateWithin` be? + newSymbol(cls, name, flags, info, privateWithin, cls.span) + + private def inlinedSymbolClassDef(cls: ClassSymbol, inlinableDecl: ClassSymbol, traitTargs: List[Type])(using Context): ClassSymbol = + def infoFn(cls1: ClassSymbol) = + inlinableDecl.info.asInstanceOf[ClassInfo].derivedClassInfo( + prefix = cls.typeRef, + declaredParents = defn.ObjectType :: cls.thisType.select(inlinableDecl) :: Nil, + decls = newScope, + // selfInfo = , + ) + + val newCls = newClassSymbol( + owner = cls, + name = inlinableDecl.name.toTypeName, + flags = inlinableDecl.flags | Synthetic, + infoFn = infoFn, + privateWithin = NoSymbol, + coord = cls.coord + ) + + newConstructor( + newCls, + flags = EmptyFlags, + paramNames = Nil, + paramTypes = Nil, + privateWithin = NoSymbol, + coord = newCls.coord + ).entered + + for + decl <- inlinableDecl.info.decls.toList + if decl.isTerm && !decl.isConstructor && !decl.is(ParamAccessor) + do + inlinedSymbolValOrDef(newCls, decl, traitTargs).entered + + newCls + end inlinedSymbolClassDef + + def inlinedDefs(cls: ClassSymbol)(using Context): List[Tree] = + atPhase(ctx.phase.next) { cls.info.decls.toList } + .filter(sym => sym.is(Synthetic) && (atPhase(ctx.phase.next) { sym.nextOverriddenSymbol }.maybeOwner.isInlineTrait)) + .map { sym => + if sym.isClass then inlinedClassDefs(cls, sym.asClass) + else inlinedValOrDefDefs(cls, sym) + } + + private def inlinedValOrDefDefs(cls: ClassSymbol, inlinedDecl: Symbol)(using Context): Tree = + val inlinableDecl = inlinedDecl.allOverriddenSymbols.find { sym => + !sym.is(Deferred) && sym.owner.isInlineTrait + }.getOrElse(inlinedDecl.nextOverriddenSymbol) + val parent = mixinParentTypeOf(inlinedDecl.owner.asClass, inlinableDecl.owner.asClass).typeSymbol.name.asTypeName + valOrDefDefInlineOverride(cls, inlinedDecl, parent, inlinableDecl) + + private def inlinedClassDefs(cls: ClassSymbol, inlinedDecl: ClassSymbol)(using Context): Tree = + val parent = inlinedDecl.info.parents.last.typeSymbol + val members = parent.info.decls.toList.filterNot(_.is(ParamAccessor)).zip(inlinedDecl.info.decls.toList).collect { + case (overridden, decl) if decl.isTerm && !decl.isConstructor && !decl.is(ParamAccessor) => + assert(overridden.name == decl.name, (overridden, decl)) // TODO find better wy to recover `overridden` from `decl` + val parent = mixinParentTypeOf(decl.owner.asClass, overridden.owner.asClass).typeSymbol.name.asTypeName + valOrDefDefInlineOverride(cls, decl, parent, overridden) + } + ClassDef( + inlinedDecl.asClass, + DefDef(inlinedDecl.primaryConstructor.asTerm), + body = members, + superArgs = List.empty[Tree] + ).withSpan(inlinedDecl.span) + + private def valOrDefDefInlineOverride(cls: ClassSymbol, decl: Symbol, parent: TypeName, overridden: Symbol)(using Context): Tree = + def rhs(argss: List[List[Tree]])(using Context) = + if decl.is(Deferred) then EmptyTree + else if decl.is(Mutable) && decl.name.isSetterName then Literal(Constant(())) + else + ctx.compilationUnit.needsInlining = true + Super(This(ctx.owner.owner.asClass), parent).select(overridden).appliedToArgss(argss) + + if decl.is(Method) then DefDef(decl.asTerm, rhs(_)(using ctx.withOwner(decl))).withSpan(cls.span) + else ValDef(decl.asTerm, rhs(Nil)(using ctx.withOwner(decl))).withSpan(cls.span) + + private def mixinParentTypeOf(cls: ClassSymbol, baseClass: ClassSymbol)(using Context): Type = + cls.info.parents.findLast(parent => parent.typeSymbol.derivesFrom(baseClass)).get + + /** Register inline members RHS in `@bodyAnnotation`s */ + def registerInlineTraitInfo(stats: List[Tree])(using Context): Unit = + for stat <- stats do + stat match + case stat: ValOrDefDef if !stat.symbol.is(Inline) && !stat.symbol.is(Deferred) => + // TODO? val rhsToInline = PrepareInlineable.wrapRHS(stat, stat.tpt, stat.rhs) + PrepareInlineable.registerInlineInfo(stat.symbol, stat.rhs/*TODO? rhsToInline*/) + case TypeDef(_, rhs: Template) => + registerInlineTraitInfo(rhs.body) + case _ => + + /** Checks if members are supported in inline traits */ + def checkValidInlineTraitMember(stats: List[Tree])(using Context): Unit = + for stat <- stats do + val sym = stat.symbol + stat match + case stat: ValOrDefDef => + if sym.is(Module) then report.error(em"Implementation restriction: object cannot be defined in inline traits", stat.srcPos) + // else if sym.is(Private) then report.error(em"Implementation restriction: private ${sym.kindString} cannot be defined in inline traits", stat.srcPos) + else () // Ok + case stat: TypeDef => + if sym.isClass && !sym.is(Trait) then report.error(em"Implementation restriction: ${sym.kindString} cannot be defined in inline traits", stat.srcPos) + else () // OK + case _: Import => + report.error(em"Implementation restriction: import cannot be defined in inline traits", stat.srcPos) + case _: Export => + report.error(em"Implementation restriction: export cannot be defined in inline traits", stat.srcPos) + case _ => + report.error(em"Implementation restriction: statements cannot be added to inline traits", stat.srcPos) diff --git a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala index fffe87c3f57a..4200f1c21cae 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala @@ -29,27 +29,29 @@ object Inlines: */ private[dotc] class MissingInlineInfo extends Exception - /** `sym` is an inline method with a known body to inline. - */ - def hasBodyToInline(sym: SymDenotation)(using Context): Boolean = - sym.isInlineMethod && sym.hasAnnotation(defn.BodyAnnot) - /** The body to inline for method `sym`, or `EmptyTree` if none exists. - * @pre hasBodyToInline(sym) */ def bodyToInline(sym: SymDenotation)(using Context): Tree = - if hasBodyToInline(sym) then - sym.getAnnotation(defn.BodyAnnot).get.tree - else - EmptyTree + sym.getAnnotation(defn.BodyAnnot).map(_.tree).getOrElse(EmptyTree) /** Are we in an inline method body? */ def inInlineMethod(using Context): Boolean = ctx.owner.ownersIterator.exists(_.isInlineMethod) + /** Are we in an inline method or trait body? */ + def inInlineContext(using Context): Boolean = + ctx.owner.ownersIterator.exists(sym => sym.isInlineMethod || sym.isInlineTrait) + /** Can a call to method `meth` be inlined? */ def isInlineable(meth: Symbol)(using Context): Boolean = - meth.is(Inline) && meth.hasAnnotation(defn.BodyAnnot) && !inInlineMethod + def isSuperCallInInlineTraitGeneratedMethod = + meth.ownersIterator.exists(_.isInlineTrait) + && ctx.owner.is(Synthetic) + && ctx.owner.owner.isClass + && ctx.owner.overriddenSymbol(meth.owner.asClass) == meth + (meth.is(Inline) || isSuperCallInInlineTraitGeneratedMethod) + && meth.hasAnnotation(defn.BodyAnnot) + && !inInlineContext /** Should call be inlined in this context? */ def needsInlining(tree: Tree)(using Context): Boolean = tree match { diff --git a/compiler/src/dotty/tools/dotc/inlines/PrepareInlineable.scala b/compiler/src/dotty/tools/dotc/inlines/PrepareInlineable.scala index 1acc6a1c8317..18f4b4fa2d5f 100644 --- a/compiler/src/dotty/tools/dotc/inlines/PrepareInlineable.scala +++ b/compiler/src/dotty/tools/dotc/inlines/PrepareInlineable.scala @@ -245,7 +245,7 @@ object PrepareInlineable { isLocalOrParam(sym, inlineMethod) && !(sym.is(Param) && sym.owner == inlineMethod) /** The type ascription `rhs: tpt`, unless `original` is `transparent`. */ - def wrapRHS(original: untpd.DefDef, tpt: Tree, rhs: Tree)(using Context): Tree = + def wrapRHS(original: untpd.ValOrDefDef, tpt: Tree, rhs: Tree)(using Context): Tree = if original.mods.is(Transparent) then rhs else Typed(rhs, tpt) /** Return result of evaluating `op`, but drop `Inline` flag and `Body` annotation diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 2f3daa79fb07..3aecfb2d68ab 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -3924,7 +3924,7 @@ object Parsers { } } - /** TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef + /** TmplDef ::= ([‘case’] ‘class’ | [‘inline’] ‘trait’) ClassDef * | [‘case’] ‘object’ ObjectDef * | ‘enum’ EnumDef * | ‘given’ GivenDef diff --git a/compiler/src/dotty/tools/dotc/transform/DeferInlineTraits.scala b/compiler/src/dotty/tools/dotc/transform/DeferInlineTraits.scala new file mode 100644 index 000000000000..39a12f14e416 --- /dev/null +++ b/compiler/src/dotty/tools/dotc/transform/DeferInlineTraits.scala @@ -0,0 +1,47 @@ +package dotty.tools.dotc +package transform + +import core._ +import Contexts._ +import DenotTransformers.SymTransformer +import Flags._ +import SymDenotations._ +import Symbols._ +import MegaPhase.MiniPhase +import ast.tpd + +class DeferInlineTraits extends MiniPhase with SymTransformer: + import tpd._ + import DeferInlineTraits._ + + override def phaseName: String = DeferInlineTraits.name + + override def description: String = DeferInlineTraits.description + + override def transformSym(sym: SymDenotation)(using Context): SymDenotation = + if isEraseable(sym) then sym.copySymDenotation(initFlags = sym.flags &~ Final | Deferred) + else sym + + override def transformValDef(tree: ValDef)(using Context): ValDef = + if isEraseable(tree.symbol) then cpy.ValDef(tree)(rhs = EmptyTree) + else tree + + override def transformDefDef(tree: DefDef)(using Context): DefDef = + if isEraseable(tree.symbol) then cpy.DefDef(tree)(rhs = EmptyTree) + else tree + + private def isEraseable(sym: SymDenotation)(using Context): Boolean = + sym.isTerm + && !sym.isConstructor + && !sym.is(Param) + && !sym.is(ParamAccessor) + && !sym.is(Private) + && !sym.isLocalDummy + && sym.ownersIterator.exists(_.isInlineTrait) + + +object DeferInlineTraits: + import tpd._ + + val name: String = "deferInlineTraits" + val description: String = "defer all members in inline traits" diff --git a/compiler/src/dotty/tools/dotc/transform/Devirtualize.scala b/compiler/src/dotty/tools/dotc/transform/Devirtualize.scala new file mode 100644 index 000000000000..501d57fd3abb --- /dev/null +++ b/compiler/src/dotty/tools/dotc/transform/Devirtualize.scala @@ -0,0 +1,38 @@ +package dotty.tools +package dotc +package transform + +import core.* +import Flags.* +import MegaPhase.* +import Symbols.*, Contexts.*, Types.*, Decorators.* +import StdNames.nme +import ast.TreeTypeMap +import Constants.Constant + +import scala.collection.mutable.ListBuffer + +/** Devirtualize method calls. + * + * If we have a `x.m` for `x: X` where `X <: T` and `m` is a member of `T` + * that is overwritten in `X`, then we can replace `x.m` with `X.m`. + */ +class Devirtualize extends MiniPhase: + import ast.tpd.* + + override def phaseName: String = Devirtualize.name + + override def description: String = Devirtualize.description + + override def transformSelect(tree: Select)(using Context): Tree = + val sym = tree.symbol + val qualTypeSym = tree.qualifier.tpe.widenDealias.typeSymbol + if !(sym.isTerm && sym.owner.isClass) || sym.maybeOwner.eq(qualTypeSym) || !qualTypeSym.isClass then tree + else + val devirtualizedSym = sym.overriddenSymbol(qualTypeSym.asClass) + if !devirtualizedSym.exists || sym.eq(devirtualizedSym) || devirtualizedSym.isAllOf(Mutable | JavaDefined) then tree + else tree.withType(devirtualizedSym.termRef) + +object Devirtualize: + val name: String = "devirtualize" + val description: String = "try to defirualize call to methods" diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index 8bfbb90a0700..3778f5993726 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -44,7 +44,7 @@ class Erasure extends Phase with DenotTransformer { override def description: String = Erasure.description /** List of names of phases that should precede this phase */ - override def runsAfter: Set[String] = Set(InterceptedMethods.name, ElimRepeated.name) + override def runsAfter: Set[String] = Set(InterceptedMethods.name, ElimRepeated.name, Devirtualize.name) override def changesMembers: Boolean = true // the phase adds bridges override def changesParents: Boolean = true // the phase drops Any diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala index 55a692780b85..dd50b9e36351 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -49,7 +49,7 @@ class ExplicitOuter extends MiniPhase with InfoTransformer { thisPhase => /** Add outer accessors if a class always needs an outer pointer */ override def transformInfo(tp: Type, sym: Symbol)(using Context): Type = tp match { - case tp @ ClassInfo(_, cls, _, decls, _) if needsOuterAlways(cls) => + case tp @ ClassInfo(_, cls, _, decls, _) if needsOuterAlways(cls) && !cls.maybeOwner.isInlineTrait => val newDecls = decls.cloneScope newOuterAccessors(cls).foreach(newDecls.enter) tp.derivedClassInfo(decls = newDecls) @@ -77,7 +77,8 @@ class ExplicitOuter extends MiniPhase with InfoTransformer { thisPhase => ensureOuterAccessors(cls) val clsHasOuter = hasOuter(cls) - if (clsHasOuter || cls.mixins.exists(needsOuterIfReferenced)) { + if cls.maybeOwner.isInlineTrait then impl + else if (clsHasOuter || cls.mixins.exists(needsOuterIfReferenced)) { val newDefs = new mutable.ListBuffer[Tree] if (clsHasOuter) diff --git a/compiler/src/dotty/tools/dotc/transform/Inlining.scala b/compiler/src/dotty/tools/dotc/transform/Inlining.scala index 94df114290e4..1a3c2a3ba734 100644 --- a/compiler/src/dotty/tools/dotc/transform/Inlining.scala +++ b/compiler/src/dotty/tools/dotc/transform/Inlining.scala @@ -11,9 +11,11 @@ import dotty.tools.dotc.ast.Trees.* import dotty.tools.dotc.quoted.* import dotty.tools.dotc.inlines.Inlines import dotty.tools.dotc.ast.TreeMapWithImplicits +import dotty.tools.dotc.core.Decorators.* import dotty.tools.dotc.core.DenotTransformers.IdentityDenotTransformer import dotty.tools.dotc.staging.StagingLevel + import scala.collection.mutable.ListBuffer /** Inlines all calls to inline methods that are not in an inline method or a quote */ @@ -46,7 +48,7 @@ class Inlining extends MacroTransform, IdentityDenotTransformer { new TreeTraverser { def traverse(tree: Tree)(using Context): Unit = tree match - case tree: RefTree if !Inlines.inInlineMethod && StagingLevel.level == 0 => + case tree: RefTree if !Inlines.inInlineContext && StagingLevel.level == 0 => assert(!tree.symbol.isInlineMethod, tree.show) case _ => traverseChildren(tree) diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 30c994a1777c..9a252f9f29b5 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -441,9 +441,13 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase => checkMacroAnnotation(sym) if sym.isOneOf(GivenOrImplicit) then sym.keepAnnotationsCarrying(thisPhase, Set(defn.CompanionClassMetaAnnot), orNoneOf = defn.MetaAnnots) + if sym.isInlineTrait then + Feature.checkExperimentalFeature("inline trait", tree, "\nConsider using @experimental inline trait") tree.rhs match case impl: Template => for parent <- impl.parents do + if parent.symbol.isInlineTrait || (parent.symbol.isConstructor && parent.symbol.owner.isInlineTrait) then + ctx.compilationUnit.needsTraitInlining = true Checking.checkTraitInheritance(parent.tpe.classSymbol, sym.asClass, parent.srcPos) // Constructor parameters are in scope when typing a parent. // While they can safely appear in a parent tree, to preserve diff --git a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala index ce2b8fa591d8..4c4fa64436b9 100644 --- a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -107,7 +107,7 @@ class SuperAccessors(thisPhase: DenotTransformer) { val clazz = sup.symbol val currentClass = ctx.owner.enclosingClass - if (sym.isTerm && !sym.is(Method, butNot = Accessor) && !ctx.owner.isAllOf(ParamForwarder)) + if sym.isTerm && !sym.is(Method, butNot = Accessor) && !ctx.owner.isAllOf(ParamForwarder) && !sym.owner.isInlineTrait then // ParamForwaders as installed ParamForwarding.scala do use super calls to vals report.error(em"super may be not be used on ${sym.underlyingSymbol}", sel.srcPos) else if (isDisallowed(sym)) diff --git a/compiler/src/dotty/tools/dotc/transform/TraitInlining.scala b/compiler/src/dotty/tools/dotc/transform/TraitInlining.scala new file mode 100644 index 000000000000..dc442cc5fa90 --- /dev/null +++ b/compiler/src/dotty/tools/dotc/transform/TraitInlining.scala @@ -0,0 +1,91 @@ +package dotty.tools.dotc +package transform + +import core.* +import Flags.* +import Contexts.* +import Symbols.* + +import dotty.tools.dotc.ast.tpd +import dotty.tools.dotc.ast.Trees.* +import dotty.tools.dotc.quoted.* +import dotty.tools.dotc.inlines.InlineTraits.* +import dotty.tools.dotc.ast.TreeMapWithImplicits +import dotty.tools.dotc.core.NameOps.* +import dotty.tools.dotc.core.Decorators.* +import dotty.tools.dotc.core.DenotTransformers.DenotTransformer +import dotty.tools.dotc.core.Denotations.SingleDenotation +import dotty.tools.dotc.core.SymDenotations.SymDenotation +import dotty.tools.dotc.core.Types.* +import dotty.tools.dotc.staging.StagingLevel +import dotty.tools.dotc.core.Constants.* + +import scala.collection.mutable.ListBuffer +import javax.xml.transform.Templates + +/** TODO */ +class TraitInlining extends MacroTransform, DenotTransformer { + self => + + import tpd.* + + override def phaseName: String = TraitInlining.name + + override def description: String = TraitInlining.description + + override def allowsImplicitSearch: Boolean = true + + override def changesMembers: Boolean = true + + override def run(using Context): Unit = + if ctx.compilationUnit.needsTraitInlining then + try super.run + catch case _: CompilationUnit.SuspendException => () + + override def runOn(units: List[CompilationUnit])(using Context): List[CompilationUnit] = + val newUnits = super.runOn(units).filterNot(_.suspended) + newUnits + + override def checkPostCondition(tree: Tree)(using Context): Unit = + () // TODO + + def newTransformer(using Context): Transformer = new Transformer { + override def transform(tree: tpd.Tree)(using Context): tpd.Tree = + tree match + case tree: Template if needsTraitInlining(ctx.owner.asClass) => + cpy.Template(tree)(body = inlinedDefs(ctx.owner.asClass) ::: tree.body) + case _ => + super.transform(tree) + } + + def transform(ref: SingleDenotation)(using Context): SingleDenotation = { + val sym = ref.symbol + ref match { + case ref: SymDenotation if sym.isClass && !sym.is(Module) && sym.maybeOwner.isInlineTrait => + val newName = + if sym.is(Module) then (sym.name.toString + "inline$trait$").toTypeName // TODO use NameKinds + else (sym.name.toString + "$inline$trait").toTypeName // TODO use NameKinds + ref.copySymDenotation(name = newName) + case ref: SymDenotation => + ref.info match + case tp @ ClassInfo(_, cls, _, decls, _) if needsTraitInlining(sym.asClass) => + val newDecls = decls.cloneScope + inlinedMemberSymbols(sym.asClass).foreach(newDecls.enter) + inlinedPrivateMemberSymbols(sym.asClass).foreach(newDecls.enter) + val newInfo = tp.derivedClassInfo(decls = newDecls) + ref.copySymDenotation(info = newInfo).copyCaches(ref, ctx.phase.next) + case _ if ref.isTerm && ref.owner.isInlineTrait && ref.is(Private) => + val newName = (sym.name.expandedName(ref.owner).toString + "$inline$trait").toTermName // TODO use NameKinds + ref.copySymDenotation(name = newName, initFlags = ref.flags &~ Private) + case _ => + ref + case _ => + ref + } + } + +} + +object TraitInlining: + val name: String = "traitInlining" + val description: String = "generate inline trait members" diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 96e2e937927d..a66409c01144 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -583,7 +583,7 @@ object Checking { if (sym.isConstructor && !sym.isPrimaryConstructor && sym.owner.is(Trait, butNot = JavaDefined)) val addendum = if ctx.settings.Ydebug.value then s" ${sym.owner.flagsString}" else "" fail(em"Traits cannot have secondary constructors$addendum") - checkApplicable(Inline, sym.isTerm && !sym.isOneOf(Mutable | Module)) + checkApplicable(Inline, sym.isTerm && !sym.isOneOf(Mutable | Module) || sym.is(Trait)) checkApplicable(Lazy, !sym.isOneOf(Method | Mutable)) if (sym.isType && !sym.isOneOf(Deferred | JavaDefined)) for (cls <- sym.allOverriddenSymbols.filter(_.isClass)) { diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index cdfd137e5661..acf0a71f242e 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -428,6 +428,9 @@ object RefChecks { def otherTp(self: Type) = self.memberInfo(other) + def isInlinedFromInlineTrait = + member.is(Synthetic) && other.owner.isInlineTrait + refcheck.println(i"check override ${infoString(member)} overriding ${infoString(other)}") def noErrorType = !memberTp(self).isErroneous && !otherTp(self).isErroneous @@ -546,7 +549,7 @@ object RefChecks { overrideError("cannot be used here - opaque type aliases cannot be overridden") else if (!other.is(Deferred) && member.isClass) overrideError("cannot be used here - classes can only override abstract types") - else if other.isEffectivelyFinal then // (1.2) + else if other.isEffectivelyFinal && !isInlinedFromInlineTrait then // (1.2) overrideError(i"cannot override final member ${other.showLocated}") else if (member.is(ExtensionMethod) && !other.is(ExtensionMethod)) // (1.3) overrideError("is an extension method, cannot override a normal method") @@ -585,7 +588,7 @@ object RefChecks { overrideError("needs `override` modifier") else if (other.is(AbsOverride) && other.isIncompleteIn(clazz) && !member.is(AbsOverride)) overrideError("needs `abstract override` modifiers") - else if member.is(Override) && other.is(Mutable) then + else if member.is(Override) && other.is(Mutable) && !isInlinedFromInlineTrait then overrideError("cannot override a mutable variable") else if (member.isAnyOverride && !(member.owner.thisType.baseClasses exists (_ isSubClass other.owner)) && diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 9150ad6be392..d5cab6c37f3b 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -29,7 +29,7 @@ import Inferencing.* import Dynamic.isDynamicExpansion import EtaExpansion.etaExpand import TypeComparer.CompareResult -import inlines.{Inlines, PrepareInlineable} +import inlines.{Inlines, PrepareInlineable, InlineTraits} import util.Spans.* import util.common.* import util.{Property, SimpleIdentityMap, SrcPos} @@ -2811,7 +2811,15 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer cdef.withType(UnspecifiedErrorType) else { val dummy = localDummy(cls, impl) - val body1 = addAccessorDefs(cls, typedStats(impl.body, dummy)(using ctx.inClassContext(self1.symbol))._1) + var body1 = addAccessorDefs(cls, typedStats(impl.body, dummy)(using ctx.inClassContext(self1.symbol))._1) + + if !ctx.isAfterTyper then + if cls.isInlineTrait then + InlineTraits.checkValidInlineTraitMember(body1) + InlineTraits.registerInlineTraitInfo(body1) + else + InlineTraits.adaptNoInit(cls, parents1) + // body1 = InlineTraits.inlinedMembers(cls, parents1) ::: body1 checkNoDoubleDeclaration(cls) val impl1 = cpy.Template(impl)(constr1, parents1, Nil, self1, body1) diff --git a/tests/disabled/pos/inline-trait-3-trait-with-params.scala b/tests/disabled/pos/inline-trait-3-trait-with-params.scala new file mode 100644 index 000000000000..a497ebbcb7c1 --- /dev/null +++ b/tests/disabled/pos/inline-trait-3-trait-with-params.scala @@ -0,0 +1,13 @@ +inline trait A[T](a: T): + def f: T = a + def f(x: T): T = x + def f[U <: T](x: U, y: T): T = x +end A + +class B extends A[Int](3): + /* + override def f: Int = ??? + override def f(x: Int): Int = ??? + override def f[U <: Int](x: U, y: Int): Int = ??? + */ +end B diff --git a/tests/disabled/pos/inline-trait-4-inner-class.scala b/tests/disabled/pos/inline-trait-4-inner-class.scala new file mode 100644 index 000000000000..b3c25e75de4c --- /dev/null +++ b/tests/disabled/pos/inline-trait-4-inner-class.scala @@ -0,0 +1,20 @@ +inline trait Options[+T]: + sealed trait Option: + def get: T + def isEmpty: Boolean + + class Some(x: T) extends Option: + def get: T = x + def isEmpty: Boolean = false + + object None extends Option: + def get: T = throw new NoSuchElementException("None.get") + def isEmpty: Boolean = true +end Options + +object IntOptions extends Options[Int] +import IntOptions._ + +val o1: Option = Some(1) // specialized +val o2: Option = None +val x1: Int = o1.get // no unboxing diff --git a/tests/disabled/pos/inline-trait-body-class-abstract.scala b/tests/disabled/pos/inline-trait-body-class-abstract.scala new file mode 100644 index 000000000000..4704b324e26d --- /dev/null +++ b/tests/disabled/pos/inline-trait-body-class-abstract.scala @@ -0,0 +1,10 @@ +inline trait A: + class InnerA: + def foo(): Int + def bar = foo() + 1 + +class B extends A: + class InnerB extends InnerA: + def foo(): Int = -23 + + def f = InnerB().bar \ No newline at end of file diff --git a/tests/disabled/pos/inline-trait-body-class-case.scala b/tests/disabled/pos/inline-trait-body-class-case.scala new file mode 100644 index 000000000000..79bade9a9036 --- /dev/null +++ b/tests/disabled/pos/inline-trait-body-class-case.scala @@ -0,0 +1,5 @@ +inline trait A: + case class Inner(val x: Int) + +class B extends A: + def f = Inner(17).x \ No newline at end of file diff --git a/tests/disabled/pos/inline-trait-body-class-enum.scala b/tests/disabled/pos/inline-trait-body-class-enum.scala new file mode 100644 index 000000000000..a114ff396067 --- /dev/null +++ b/tests/disabled/pos/inline-trait-body-class-enum.scala @@ -0,0 +1,6 @@ +inline trait A: + enum Inner: + case A, B, C + +class B extends A: + def f = Inner.B \ No newline at end of file diff --git a/tests/disabled/pos/inline-trait-body-class-extends-inline-trait.scala b/tests/disabled/pos/inline-trait-body-class-extends-inline-trait.scala new file mode 100644 index 000000000000..1f1a3836fa98 --- /dev/null +++ b/tests/disabled/pos/inline-trait-body-class-extends-inline-trait.scala @@ -0,0 +1,11 @@ +inline trait A: + class Inner extends Trait[Int]: + val x = 1 + +inline trait Trait[T]: + def f(x: T): T = x + +class B extends A: + val inner = Inner() + def x = inner.x + def f = inner.f(x) \ No newline at end of file diff --git a/tests/disabled/pos/inline-trait-body-class-generic.scala b/tests/disabled/pos/inline-trait-body-class-generic.scala new file mode 100644 index 000000000000..859b7ac63b9f --- /dev/null +++ b/tests/disabled/pos/inline-trait-body-class-generic.scala @@ -0,0 +1,6 @@ +inline trait A: + class Inner[T <: Int]: + val x: T = 1 + +class B extends A: + def f = Inner[Int]().x \ No newline at end of file diff --git a/tests/disabled/pos/inline-trait-body-class-object.scala b/tests/disabled/pos/inline-trait-body-class-object.scala new file mode 100644 index 000000000000..dc990c69573c --- /dev/null +++ b/tests/disabled/pos/inline-trait-body-class-object.scala @@ -0,0 +1,6 @@ +inline trait A[T]: + object Inner: + val x: T = ??? + +class B extends A[Int]: + def i: Int = Inner.x diff --git a/tests/disabled/pos/inline-trait-body-class-params.scala b/tests/disabled/pos/inline-trait-body-class-params.scala new file mode 100644 index 000000000000..114d8811da2d --- /dev/null +++ b/tests/disabled/pos/inline-trait-body-class-params.scala @@ -0,0 +1,5 @@ +inline trait A: + class Inner(val x: Int) + +class B extends A: + def f = Inner(17).x \ No newline at end of file diff --git a/tests/disabled/pos/inline-trait-body-class-sealed.scala b/tests/disabled/pos/inline-trait-body-class-sealed.scala new file mode 100644 index 000000000000..ff28d164c617 --- /dev/null +++ b/tests/disabled/pos/inline-trait-body-class-sealed.scala @@ -0,0 +1,7 @@ +inline trait A: + sealed class InnerA: + val x = 1 + +class B extends A: + class InnerB extends InnerA + def f = InnerB().x \ No newline at end of file diff --git a/tests/disabled/pos/inline-trait-body-class-simple.scala b/tests/disabled/pos/inline-trait-body-class-simple.scala new file mode 100644 index 000000000000..56476b96b44b --- /dev/null +++ b/tests/disabled/pos/inline-trait-body-class-simple.scala @@ -0,0 +1,6 @@ +inline trait A: + class Inner: + val x = 1 + +class B extends A: + def f = Inner().x \ No newline at end of file diff --git a/tests/disabled/pos/inline-trait-body-def-generic.scala b/tests/disabled/pos/inline-trait-body-def-generic.scala new file mode 100644 index 000000000000..e7d339cb62ee --- /dev/null +++ b/tests/disabled/pos/inline-trait-body-def-generic.scala @@ -0,0 +1,6 @@ +inline trait A: + def foo[T] = 1 + def bar: [U <: A] => U => Int = [U <: A] => (x: U) => x.foo + +class B extends A: + def f = foo[String] + bar(this) diff --git a/tests/disabled/pos/inline-trait-body-trait-inline.scala b/tests/disabled/pos/inline-trait-body-trait-inline.scala new file mode 100644 index 000000000000..e255bd6ba42c --- /dev/null +++ b/tests/disabled/pos/inline-trait-body-trait-inline.scala @@ -0,0 +1,7 @@ +inline trait A: + inline trait InnerA: + val x = 1 + +class B extends A: + class InnerB extends InnerA + def f = InnerB().x \ No newline at end of file diff --git a/tests/disabled/pos/inline-trait-signature-generic-context-bound.scala b/tests/disabled/pos/inline-trait-signature-generic-context-bound.scala new file mode 100644 index 000000000000..f3587911f168 --- /dev/null +++ b/tests/disabled/pos/inline-trait-signature-generic-context-bound.scala @@ -0,0 +1,4 @@ +inline trait A[T: List] + +given List[Int] = Nil +class B extends A \ No newline at end of file diff --git a/tests/disabled/pos/inline-trait-signature-parameters-using-nameless.scala b/tests/disabled/pos/inline-trait-signature-parameters-using-nameless.scala new file mode 100644 index 000000000000..1882b0348488 --- /dev/null +++ b/tests/disabled/pos/inline-trait-signature-parameters-using-nameless.scala @@ -0,0 +1,4 @@ +inline trait A(using Int) // error + +given x: Int = 1 +class B extends A \ No newline at end of file diff --git a/tests/disabled/pos/inline-trait-signature-parameters-val-private.scala b/tests/disabled/pos/inline-trait-signature-parameters-val-private.scala new file mode 100644 index 000000000000..9306e0152f05 --- /dev/null +++ b/tests/disabled/pos/inline-trait-signature-parameters-val-private.scala @@ -0,0 +1,3 @@ +inline trait A(x: Int) + +class B extends A(1) \ No newline at end of file diff --git a/tests/disabled/run/inline-trait-inheritance-inline-grandparent.scala b/tests/disabled/run/inline-trait-inheritance-inline-grandparent.scala new file mode 100644 index 000000000000..adc00b7b7bfe --- /dev/null +++ b/tests/disabled/run/inline-trait-inheritance-inline-grandparent.scala @@ -0,0 +1,33 @@ +package simpleGrandParent: + inline trait SimpleGrandParent[T]: + def foo(): Int = 0 + def foooo(): T = ??? + + inline trait SimpleParent[T, U](x: T, z: U) extends SimpleGrandParent[U]: + def bar(a: T) = (a, x) + + class SimpleC extends SimpleParent("Hello", 1234) + +package grandParentWithArgs: + inline trait GrandParent[T](val x: T, val y: T): + def foo(): T = x + def foooo(): T = y + + inline trait Parent[T, U](x: T, z: U) extends GrandParent[U]: + def bar(a: T) = (a, x, y) + + class C extends Parent("Hello", 1234), GrandParent(5678, 9) + +@main def Test = + import simpleGrandParent.SimpleC + import grandParentWithArgs.C + + val simpleC = SimpleC() + println(simpleC.foo()) + println(simpleC.bar("Test SimpleC")) + println + + val c = C() + println(c.foo()) + println(c.bar("Test C")) + println(c.x) \ No newline at end of file diff --git a/tests/neg/i2421.scala b/tests/neg/i2421.scala index dc8e229f38f0..bcf3da6dbb36 100644 --- a/tests/neg/i2421.scala +++ b/tests/neg/i2421.scala @@ -1,7 +1,6 @@ inline object Foo // OK (error would be detected later, in PostTyper) inline class Bar // error: modifier(s) `inline' incompatible with type definition inline abstract class Baz // error: modifier(s) `inline' incompatible with type definition -inline trait Qux // error: modifier(s) `inline' incompatible with type definition object Quux { inline type T // error: modifier(s) `inline' incompatible with type definition diff --git a/tests/neg/inline-trait-body-override-def-final.scala b/tests/neg/inline-trait-body-override-def-final.scala new file mode 100644 index 000000000000..2455995fda44 --- /dev/null +++ b/tests/neg/inline-trait-body-override-def-final.scala @@ -0,0 +1,5 @@ +inline trait A: + final def f(x: Int) = x + +class B extends A: + override final def f(x: Int) = x + 1 // error diff --git a/tests/neg/inline-trait-body-override-val-final.scala b/tests/neg/inline-trait-body-override-val-final.scala new file mode 100644 index 000000000000..416f76a81ca4 --- /dev/null +++ b/tests/neg/inline-trait-body-override-val-final.scala @@ -0,0 +1,5 @@ +inline trait A: + final val x = 1 + +class B extends A: + override final val x = 2 // error diff --git a/tests/pos/inline-trait-1-simple-trait.scala b/tests/pos/inline-trait-1-simple-trait.scala new file mode 100644 index 000000000000..9f92bf5f90a5 --- /dev/null +++ b/tests/pos/inline-trait-1-simple-trait.scala @@ -0,0 +1,19 @@ +inline trait A: + type X = String + + val x: Int = 3 + val y: Int = x + 4 + // private val z: Int = 1 + + def f: Int = 5 + def f(x: Int): Int = x + def f[T](x: T): Int = 2 + + private[A] def g = 1 + protected def p = 123 + // private[this] def pp = 123456 + + def xx: X = "foo".asInstanceOf[X] +end A + +class B extends A diff --git a/tests/pos/inline-trait-2-generic-trait.scala b/tests/pos/inline-trait-2-generic-trait.scala new file mode 100644 index 000000000000..936d2b240641 --- /dev/null +++ b/tests/pos/inline-trait-2-generic-trait.scala @@ -0,0 +1,7 @@ +inline trait A[T]: + def f: T = f + def f(x: T): T = x + def f[U <: T](x: U, y: T): T = x +end A + +class B extends A[Int] diff --git a/tests/pos/inline-trait-3-trait-params.scala b/tests/pos/inline-trait-3-trait-params.scala new file mode 100644 index 000000000000..db29a4f54f85 --- /dev/null +++ b/tests/pos/inline-trait-3-trait-params.scala @@ -0,0 +1,8 @@ +import scala.annotation.publicInBinary + +inline trait A(@publicInBinary private[A] val a: Int): // TODO remove `val`? + def f: Int = a + def g(b: Int): Int = a + b +end A + +class B extends A(4) diff --git a/tests/pos/inline-trait-4-no-inner-class.scala b/tests/pos/inline-trait-4-no-inner-class.scala new file mode 100644 index 000000000000..f626ac73e469 --- /dev/null +++ b/tests/pos/inline-trait-4-no-inner-class.scala @@ -0,0 +1,26 @@ +import scala.annotation.publicInBinary + +inline trait Option[+T]: + def get: T + def isEmpty: Boolean +end Option + +inline trait Some[+T](@publicInBinary private[Some] val x: T) extends Option[T]: + def get: T = x + def isEmpty: Boolean = false +end Some + +inline trait None extends Option[Nothing]: + def get: Nothing = throw new NoSuchElementException("None.get") + def isEmpty: Boolean = true +end None + +sealed trait IntOption extends Option[Int] +class IntSome(i: Int) extends IntOption, Some[Int](i) +object IntNone extends IntOption, None + +val o1: IntOption = IntSome(1) // specialized +val o2: IntOption = IntNone +val o3: Some[Int] = IntSome(1) // non-specialized +val x1: Int = o1.get // no unboxing +val x3: Int = o3.get // unboxing diff --git a/tests/pos/inline-trait-body-abstract-def.scala b/tests/pos/inline-trait-body-abstract-def.scala new file mode 100644 index 000000000000..ec412c78cc0f --- /dev/null +++ b/tests/pos/inline-trait-body-abstract-def.scala @@ -0,0 +1,6 @@ +inline trait A[T]: + def x: T + +class B extends A[Int]: + def x = 1 + def f: Int = x diff --git a/tests/pos/inline-trait-body-def-context-bound.scala b/tests/pos/inline-trait-body-def-context-bound.scala new file mode 100644 index 000000000000..7a1d4e4d1c1b --- /dev/null +++ b/tests/pos/inline-trait-body-def-context-bound.scala @@ -0,0 +1,6 @@ +inline trait A: + given List[String] = "AAA" :: Nil + def foo[T: List](x: T): T = summon[List[T]].headOption.getOrElse(x) + +class B extends A: + def f = foo("BBB") diff --git a/tests/pos/inline-trait-body-def-curried-params.scala b/tests/pos/inline-trait-body-def-curried-params.scala new file mode 100644 index 000000000000..d253aa035331 --- /dev/null +++ b/tests/pos/inline-trait-body-def-curried-params.scala @@ -0,0 +1,8 @@ +inline trait A: + def x(foo: Int)(bar: Int) = + foo + bar + + def y(foo: Int) = x(foo)(foo) + +class B extends A: + def f = x(1)(2) diff --git a/tests/pos/inline-trait-body-def-extension-method.scala b/tests/pos/inline-trait-body-def-extension-method.scala new file mode 100644 index 000000000000..1066ca159cab --- /dev/null +++ b/tests/pos/inline-trait-body-def-extension-method.scala @@ -0,0 +1,6 @@ +inline trait A: + extension [T](x: T) + def foo[U](y: U)(z: T): (T, U, T) = (x, y, z) + +class B extends A: + def f = 1.foo("2")(3) diff --git a/tests/pos/inline-trait-body-def-final.scala b/tests/pos/inline-trait-body-def-final.scala new file mode 100644 index 000000000000..1e088c38dc0f --- /dev/null +++ b/tests/pos/inline-trait-body-def-final.scala @@ -0,0 +1,4 @@ +inline trait A: + final def f(x: Int) = x + +class B extends A diff --git a/tests/pos/inline-trait-body-def-generic-singleton.scala b/tests/pos/inline-trait-body-def-generic-singleton.scala new file mode 100644 index 000000000000..be2a57de360a --- /dev/null +++ b/tests/pos/inline-trait-body-def-generic-singleton.scala @@ -0,0 +1,7 @@ +inline trait A: + def foo: 3 = 3 + def bar[T](x: T): T = x + +class B extends A: + def f: "A" = bar("A") + def g: 3 = foo diff --git a/tests/pos/inline-trait-body-def-implicit.scala b/tests/pos/inline-trait-body-def-implicit.scala new file mode 100644 index 000000000000..b80bf9bba671 --- /dev/null +++ b/tests/pos/inline-trait-body-def-implicit.scala @@ -0,0 +1,6 @@ +inline trait A: + implicit val x: String = "AAA" + def foo(implicit s: String): String = s + s + +class B extends A: + def f = foo diff --git a/tests/pos/inline-trait-body-def-inline-abstract.scala b/tests/pos/inline-trait-body-def-inline-abstract.scala new file mode 100644 index 000000000000..57e96276a901 --- /dev/null +++ b/tests/pos/inline-trait-body-def-inline-abstract.scala @@ -0,0 +1,6 @@ +inline trait A: + inline def x: Int + +class B extends A: + inline def x = 1 + def f = x diff --git a/tests/pos/inline-trait-body-def-inline-compiletime.scala b/tests/pos/inline-trait-body-def-inline-compiletime.scala new file mode 100644 index 000000000000..3bd49f2b5db8 --- /dev/null +++ b/tests/pos/inline-trait-body-def-inline-compiletime.scala @@ -0,0 +1,9 @@ +import scala.compiletime.* + +inline trait A: + inline def f[T <: String] = + inline if constValue[T] == "I consent" then "All is OK!" + else error("You must consent!") + +class B extends A: + val x = f["I consent"] diff --git a/tests/pos/inline-trait-body-def-inline-transparent.scala b/tests/pos/inline-trait-body-def-inline-transparent.scala new file mode 100644 index 000000000000..a89577daeae9 --- /dev/null +++ b/tests/pos/inline-trait-body-def-inline-transparent.scala @@ -0,0 +1,5 @@ +inline trait A: + transparent inline def x = 1 + +class B extends A: + def f: 1 = x diff --git a/tests/pos/inline-trait-body-def-inline.scala b/tests/pos/inline-trait-body-def-inline.scala new file mode 100644 index 000000000000..97e7e8e4d868 --- /dev/null +++ b/tests/pos/inline-trait-body-def-inline.scala @@ -0,0 +1,5 @@ +inline trait A: + inline def x = 1 + +class B extends A: + def f = x diff --git a/tests/pos/inline-trait-body-def-lambda.scala b/tests/pos/inline-trait-body-def-lambda.scala new file mode 100644 index 000000000000..e99ab12d122a --- /dev/null +++ b/tests/pos/inline-trait-body-def-lambda.scala @@ -0,0 +1,5 @@ +inline trait A: + def f = (i: Int) => i + +class B extends A: + def g = f diff --git a/tests/pos/inline-trait-body-def-local-val.scala b/tests/pos/inline-trait-body-def-local-val.scala new file mode 100644 index 000000000000..b89deedd0dbf --- /dev/null +++ b/tests/pos/inline-trait-body-def-local-val.scala @@ -0,0 +1,7 @@ +inline trait A: + def f = + val foo = 1 + foo + +class B extends A: + def g = f diff --git a/tests/pos/inline-trait-body-def-params.scala b/tests/pos/inline-trait-body-def-params.scala new file mode 100644 index 000000000000..3f05ec350f5e --- /dev/null +++ b/tests/pos/inline-trait-body-def-params.scala @@ -0,0 +1,7 @@ +inline trait A: + def x(foo: Int, bar: Unit) = + bar + foo + +class B extends A: + def f = x(1, ()) diff --git a/tests/pos/inline-trait-body-def-parens.scala b/tests/pos/inline-trait-body-def-parens.scala new file mode 100644 index 000000000000..65d6cdc6fb54 --- /dev/null +++ b/tests/pos/inline-trait-body-def-parens.scala @@ -0,0 +1,5 @@ +inline trait A: + def x() = 1 + +class B extends A: + def f = x() diff --git a/tests/pos/inline-trait-body-def-refinement.scala b/tests/pos/inline-trait-body-def-refinement.scala new file mode 100644 index 000000000000..f809ccf0419e --- /dev/null +++ b/tests/pos/inline-trait-body-def-refinement.scala @@ -0,0 +1,9 @@ +// FIXME: scalac tests/pos/inline-trait-body-def-refinement.scala -Yforce-sbt-phases -Xprint:typer + +trait F: + def a: A + +inline trait A: + def f: F { def a: A } = ??? + +class B extends A diff --git a/tests/pos/inline-trait-body-def-simple.scala b/tests/pos/inline-trait-body-def-simple.scala new file mode 100644 index 000000000000..7f4bf06c3d05 --- /dev/null +++ b/tests/pos/inline-trait-body-def-simple.scala @@ -0,0 +1,5 @@ +inline trait A: + def x = 1 + +class B extends A: + def f = x diff --git a/tests/pos/inline-trait-body-def-using.scala b/tests/pos/inline-trait-body-def-using.scala new file mode 100644 index 000000000000..40751f202e6c --- /dev/null +++ b/tests/pos/inline-trait-body-def-using.scala @@ -0,0 +1,6 @@ +inline trait A: + given String = "AAA" + def foo(using s: String): String = s + s + +class B extends A: + def f = foo diff --git a/tests/pos/inline-trait-body-lazy-val.scala b/tests/pos/inline-trait-body-lazy-val.scala new file mode 100644 index 000000000000..a1f71019efe3 --- /dev/null +++ b/tests/pos/inline-trait-body-lazy-val.scala @@ -0,0 +1,5 @@ +inline trait A: + lazy val x = 1 + +class B extends A: + def f = x diff --git a/tests/pos/inline-trait-body-macro-suspend/Macro.scala b/tests/pos/inline-trait-body-macro-suspend/Macro.scala new file mode 100644 index 000000000000..8aa252d8b7d0 --- /dev/null +++ b/tests/pos/inline-trait-body-macro-suspend/Macro.scala @@ -0,0 +1,10 @@ +import scala.quoted.* + +inline def foo(): Int = + ${fooImpl} + +def fooImpl(using Quotes): Expr[Int] = + '{3} + +inline trait A: + val i: Int = foo() diff --git a/tests/pos/inline-trait-body-macro-suspend/Test.scala b/tests/pos/inline-trait-body-macro-suspend/Test.scala new file mode 100644 index 000000000000..5079eecd497d --- /dev/null +++ b/tests/pos/inline-trait-body-macro-suspend/Test.scala @@ -0,0 +1,2 @@ +class B extends A: + def test = foo() \ No newline at end of file diff --git a/tests/pos/inline-trait-body-macro/Macro_1.scala b/tests/pos/inline-trait-body-macro/Macro_1.scala new file mode 100644 index 000000000000..8aa252d8b7d0 --- /dev/null +++ b/tests/pos/inline-trait-body-macro/Macro_1.scala @@ -0,0 +1,10 @@ +import scala.quoted.* + +inline def foo(): Int = + ${fooImpl} + +def fooImpl(using Quotes): Expr[Int] = + '{3} + +inline trait A: + val i: Int = foo() diff --git a/tests/pos/inline-trait-body-macro/Test_2.scala b/tests/pos/inline-trait-body-macro/Test_2.scala new file mode 100644 index 000000000000..a18aec3dbe9b --- /dev/null +++ b/tests/pos/inline-trait-body-macro/Test_2.scala @@ -0,0 +1 @@ +class B extends A diff --git a/tests/pos/inline-trait-body-rhs-type.scala b/tests/pos/inline-trait-body-rhs-type.scala new file mode 100644 index 000000000000..2190f8dc91c1 --- /dev/null +++ b/tests/pos/inline-trait-body-rhs-type.scala @@ -0,0 +1,8 @@ +import scala.annotation.publicInBinary + +inline trait A[T](@publicInBinary private[A] val x: T): + def f: T = x: T + def g: T = identity[T](x) + def h: this.type = this: this.type + +class B extends A("Hello") diff --git a/tests/pos/inline-trait-body-setter.scala b/tests/pos/inline-trait-body-setter.scala new file mode 100644 index 000000000000..e60a869a566e --- /dev/null +++ b/tests/pos/inline-trait-body-setter.scala @@ -0,0 +1,6 @@ +inline trait A: + def x = 1 + def x_= (x: Int) = ??? + var y = 1 + +class B extends A diff --git a/tests/pos/inline-trait-body-type.scala b/tests/pos/inline-trait-body-type.scala new file mode 100644 index 000000000000..40e9f161b2fc --- /dev/null +++ b/tests/pos/inline-trait-body-type.scala @@ -0,0 +1,5 @@ +inline trait A[T]: + type U = String + +class B extends A[Int]: + def f: U = "ABD" diff --git a/tests/pos/inline-trait-body-val-inline.scala b/tests/pos/inline-trait-body-val-inline.scala new file mode 100644 index 000000000000..37f76fbd915c --- /dev/null +++ b/tests/pos/inline-trait-body-val-inline.scala @@ -0,0 +1,5 @@ +inline trait A: + inline val x = 1 + +class B extends A: + def f = x diff --git a/tests/pos/inline-trait-body-val.scala b/tests/pos/inline-trait-body-val.scala new file mode 100644 index 000000000000..33552386cf79 --- /dev/null +++ b/tests/pos/inline-trait-body-val.scala @@ -0,0 +1,5 @@ +inline trait A: + val x = 1 + +class B extends A: + def f = x diff --git a/tests/pos/inline-trait-body-var.scala b/tests/pos/inline-trait-body-var.scala new file mode 100644 index 000000000000..081a5eb829fe --- /dev/null +++ b/tests/pos/inline-trait-body-var.scala @@ -0,0 +1,8 @@ +inline trait A: + var x = 1 + +class B extends A: + def f = + val old = x + x += 1 + old diff --git a/tests/pos/inline-trait-multiple-files/A.scala b/tests/pos/inline-trait-multiple-files/A.scala new file mode 100644 index 000000000000..3596275f0498 --- /dev/null +++ b/tests/pos/inline-trait-multiple-files/A.scala @@ -0,0 +1,2 @@ +inline trait A: + val i: Int = 1 diff --git a/tests/pos/inline-trait-multiple-files/B.scala b/tests/pos/inline-trait-multiple-files/B.scala new file mode 100644 index 000000000000..a18aec3dbe9b --- /dev/null +++ b/tests/pos/inline-trait-multiple-files/B.scala @@ -0,0 +1 @@ +class B extends A diff --git a/tests/pos/inline-trait-multiple-stages-defs/A_1.scala b/tests/pos/inline-trait-multiple-stages-defs/A_1.scala new file mode 100644 index 000000000000..e0184485adf9 --- /dev/null +++ b/tests/pos/inline-trait-multiple-stages-defs/A_1.scala @@ -0,0 +1,12 @@ +import scala.annotation.publicInBinary + +inline trait A(@publicInBinary private[A] val x: Int): + def f: Int = 1 + def g(a: Int): Int = 2 + def h: Int + val i: Int = 3 + val j: Int + var k: Int = 4 + + inline val a = 5 + inline def b(a: Int): Int = 6 diff --git a/tests/pos/inline-trait-multiple-stages-defs/B_2.scala b/tests/pos/inline-trait-multiple-stages-defs/B_2.scala new file mode 100644 index 000000000000..b1a1d7d6af3d --- /dev/null +++ b/tests/pos/inline-trait-multiple-stages-defs/B_2.scala @@ -0,0 +1,3 @@ +class B extends A(10): + def h: Int = 11 + val j: Int = 12 diff --git a/tests/pos/inline-trait-multiple-stages-generic-defs/A_1.scala b/tests/pos/inline-trait-multiple-stages-generic-defs/A_1.scala new file mode 100644 index 000000000000..06d8909cea96 --- /dev/null +++ b/tests/pos/inline-trait-multiple-stages-generic-defs/A_1.scala @@ -0,0 +1,11 @@ +import scala.annotation.publicInBinary + +inline trait A[T](@publicInBinary private[A] val x: T): + def f: T = x + def g(a: T): T = a + def h: T + val i: T = x + val j: T + var k: T = x + + inline def b(a: T): T = x diff --git a/tests/pos/inline-trait-multiple-stages-generic-defs/B_2.scala b/tests/pos/inline-trait-multiple-stages-generic-defs/B_2.scala new file mode 100644 index 000000000000..b595626379b8 --- /dev/null +++ b/tests/pos/inline-trait-multiple-stages-generic-defs/B_2.scala @@ -0,0 +1,3 @@ +class B extends A[Int](10): + def h: Int = 11 + val j: Int = 12 diff --git a/tests/pos/inline-trait-multiple-stages/A_1.scala b/tests/pos/inline-trait-multiple-stages/A_1.scala new file mode 100644 index 000000000000..3596275f0498 --- /dev/null +++ b/tests/pos/inline-trait-multiple-stages/A_1.scala @@ -0,0 +1,2 @@ +inline trait A: + val i: Int = 1 diff --git a/tests/pos/inline-trait-multiple-stages/B_2.scala b/tests/pos/inline-trait-multiple-stages/B_2.scala new file mode 100644 index 000000000000..a18aec3dbe9b --- /dev/null +++ b/tests/pos/inline-trait-multiple-stages/B_2.scala @@ -0,0 +1 @@ +class B extends A diff --git a/tests/pos/inline-trait-signature-generic-inferred-type.scala b/tests/pos/inline-trait-signature-generic-inferred-type.scala new file mode 100644 index 000000000000..275ed0c7ec5b --- /dev/null +++ b/tests/pos/inline-trait-signature-generic-inferred-type.scala @@ -0,0 +1,5 @@ +inline trait A[T](val x: T): + def f: T = x + +class B extends A(1): + val y: Int = f diff --git a/tests/pos/inline-trait-signature-generic-invariant.scala b/tests/pos/inline-trait-signature-generic-invariant.scala new file mode 100644 index 000000000000..cc20461e716e --- /dev/null +++ b/tests/pos/inline-trait-signature-generic-invariant.scala @@ -0,0 +1,4 @@ +inline trait A[T]: + def f(x: T): T = x + +class B extends A[Int] diff --git a/tests/pos/inline-trait-signature-generic-parameter.scala b/tests/pos/inline-trait-signature-generic-parameter.scala new file mode 100644 index 000000000000..174ceba06a8c --- /dev/null +++ b/tests/pos/inline-trait-signature-generic-parameter.scala @@ -0,0 +1,5 @@ +inline trait A[T](val x: T): + def f: T = x + +class B extends A[Int](1): + val y: Int = f diff --git a/tests/pos/inline-trait-signature-generic-type-bounds.scala b/tests/pos/inline-trait-signature-generic-type-bounds.scala new file mode 100644 index 000000000000..9cf4a00c80d7 --- /dev/null +++ b/tests/pos/inline-trait-signature-generic-type-bounds.scala @@ -0,0 +1,4 @@ +inline trait A[T >: Int <: AnyVal]: + def f(x: T): T = x + +class B extends A[Int] diff --git a/tests/pos/inline-trait-signature-generic-variant.scala b/tests/pos/inline-trait-signature-generic-variant.scala new file mode 100644 index 000000000000..ae356926d63a --- /dev/null +++ b/tests/pos/inline-trait-signature-generic-variant.scala @@ -0,0 +1,8 @@ +inline trait Cov[+T]: + def f: T = ??? + +inline trait Contr[-T]: + def f(x: T) = ??? + +class A extends Cov[AnyVal] +class B extends Contr[Int] diff --git a/tests/pos/inline-trait-signature-parameters-default-value.scala b/tests/pos/inline-trait-signature-parameters-default-value.scala new file mode 100644 index 000000000000..36170c955a4e --- /dev/null +++ b/tests/pos/inline-trait-signature-parameters-default-value.scala @@ -0,0 +1,4 @@ +inline trait A(val x: Int = 4) + +class B extends A(1) +class C extends A() diff --git a/tests/pos/inline-trait-signature-parameters-implicit.scala b/tests/pos/inline-trait-signature-parameters-implicit.scala new file mode 100644 index 000000000000..97f223c9d3c7 --- /dev/null +++ b/tests/pos/inline-trait-signature-parameters-implicit.scala @@ -0,0 +1,4 @@ +inline trait A(implicit val imp: Int) + +implicit val x: Int = 1 +class B extends A diff --git a/tests/pos/inline-trait-signature-parameters-using.scala b/tests/pos/inline-trait-signature-parameters-using.scala new file mode 100644 index 000000000000..a4e1f452e211 --- /dev/null +++ b/tests/pos/inline-trait-signature-parameters-using.scala @@ -0,0 +1,4 @@ +inline trait A(using private[A] val usng: Int) + +given x: Int = 1 +class B extends A diff --git a/tests/pos/inline-trait-signature-parameters-val-protected.scala b/tests/pos/inline-trait-signature-parameters-val-protected.scala new file mode 100644 index 000000000000..a71ced9ee48d --- /dev/null +++ b/tests/pos/inline-trait-signature-parameters-val-protected.scala @@ -0,0 +1,3 @@ +inline trait A(protected val x: Int) + +class B extends A(1) diff --git a/tests/pos/inline-trait-signature-parameters-val.scala b/tests/pos/inline-trait-signature-parameters-val.scala new file mode 100644 index 000000000000..0c1afb134d0d --- /dev/null +++ b/tests/pos/inline-trait-signature-parameters-val.scala @@ -0,0 +1,3 @@ +inline trait A(val x: Int) + +class B extends A(1) diff --git a/tests/pos/inline-trait-signature-parameters-var.scala b/tests/pos/inline-trait-signature-parameters-var.scala new file mode 100644 index 000000000000..e6c79f4a9fdc --- /dev/null +++ b/tests/pos/inline-trait-signature-parameters-var.scala @@ -0,0 +1,3 @@ +inline trait A(var x: Int) + +class B extends A(1) diff --git a/tests/pos/inline-trait-signature-sealed.scala b/tests/pos/inline-trait-signature-sealed.scala new file mode 100644 index 000000000000..bf2161dc683a --- /dev/null +++ b/tests/pos/inline-trait-signature-sealed.scala @@ -0,0 +1,4 @@ +inline sealed trait A: + final def f(x: Int) = x + +class B extends A diff --git a/tests/pos/inline-trait-signature-simple.scala b/tests/pos/inline-trait-signature-simple.scala new file mode 100644 index 000000000000..6734a69a488c --- /dev/null +++ b/tests/pos/inline-trait-signature-simple.scala @@ -0,0 +1,4 @@ +inline trait A: + def i: Int = 1 + +class B extends A diff --git a/tests/pos/inline-trait-usage-extension.scala b/tests/pos/inline-trait-usage-extension.scala new file mode 100644 index 000000000000..f9f5d87d2ceb --- /dev/null +++ b/tests/pos/inline-trait-usage-extension.scala @@ -0,0 +1,3 @@ +inline trait A + +class B extends A diff --git a/tests/pos/inline-trait-usage-param-type.scala b/tests/pos/inline-trait-usage-param-type.scala new file mode 100644 index 000000000000..e04f885f1e65 --- /dev/null +++ b/tests/pos/inline-trait-usage-param-type.scala @@ -0,0 +1,3 @@ +inline trait A + +def f(a: A) = ??? diff --git a/tests/pos/inline-trait-usage-return-type.scala b/tests/pos/inline-trait-usage-return-type.scala new file mode 100644 index 000000000000..e8015b065552 --- /dev/null +++ b/tests/pos/inline-trait-usage-return-type.scala @@ -0,0 +1,3 @@ +inline trait A + +def f: A = ??? diff --git a/tests/pos/inline-trait-usage-type-bound.scala b/tests/pos/inline-trait-usage-type-bound.scala new file mode 100644 index 000000000000..480aef477603 --- /dev/null +++ b/tests/pos/inline-trait-usage-type-bound.scala @@ -0,0 +1,3 @@ +inline trait A + +type T >: A <: A diff --git a/tests/pos/inline-trait-usage-type.scala b/tests/pos/inline-trait-usage-type.scala new file mode 100644 index 000000000000..99b386c67c54 --- /dev/null +++ b/tests/pos/inline-trait-usage-type.scala @@ -0,0 +1,3 @@ +inline trait A + +type T = List[A] diff --git a/tests/run/inline-trait-body-lazy-val.scala b/tests/run/inline-trait-body-lazy-val.scala new file mode 100644 index 000000000000..346501267f48 --- /dev/null +++ b/tests/run/inline-trait-body-lazy-val.scala @@ -0,0 +1,9 @@ +inline trait A: + lazy val x = + throw new Exception + 1 + +class B extends A + +@main def Test: Unit = + val b = B() diff --git a/tests/run/inline-trait-body-override-def.scala b/tests/run/inline-trait-body-override-def.scala new file mode 100644 index 000000000000..2ec53e02e669 --- /dev/null +++ b/tests/run/inline-trait-body-override-def.scala @@ -0,0 +1,9 @@ +inline trait A: + def foo: Unit = throw Exception("I should not be run!") + +class B extends A: + override def foo: Unit = () + +@main def Test = + val b = B() + b.foo diff --git a/tests/run/inline-trait-body-override-val.check b/tests/run/inline-trait-body-override-val.check new file mode 100644 index 000000000000..0cfbf08886fc --- /dev/null +++ b/tests/run/inline-trait-body-override-val.check @@ -0,0 +1 @@ +2 diff --git a/tests/run/inline-trait-body-override-val.scala b/tests/run/inline-trait-body-override-val.scala new file mode 100644 index 000000000000..ffd71ca0df56 --- /dev/null +++ b/tests/run/inline-trait-body-override-val.scala @@ -0,0 +1,9 @@ +inline trait A: + val x: Int = 1 + +class B extends A: + override val x = 2 + +@main def Test = + val b = B() + println(b.x) diff --git a/tests/run/inline-trait-body-override-var.check b/tests/run/inline-trait-body-override-var.check new file mode 100644 index 000000000000..0cfbf08886fc --- /dev/null +++ b/tests/run/inline-trait-body-override-var.check @@ -0,0 +1 @@ +2 diff --git a/tests/run/inline-trait-body-override-var.scala b/tests/run/inline-trait-body-override-var.scala new file mode 100644 index 000000000000..32402f452c8d --- /dev/null +++ b/tests/run/inline-trait-body-override-var.scala @@ -0,0 +1,9 @@ +inline trait A: + var x: Int + +class B extends A: + var x: Int = 2 + +@main def Test = + val b = B() + println(b.x) diff --git a/tests/run/inline-trait-inheritance-inline-ancestors/inlinetraits.scala b/tests/run/inline-trait-inheritance-inline-ancestors/inlinetraits.scala new file mode 100644 index 000000000000..e695ef3efd1a --- /dev/null +++ b/tests/run/inline-trait-inheritance-inline-ancestors/inlinetraits.scala @@ -0,0 +1,47 @@ +package inlinetraits + +val inlineValues: List[Int] = + val c = C() + List(c.zero, c.eleven, c.twelve, c.thirteen, c.twentyOne, c.twentyTwo, c.thirty) + +inline trait T0: + def zero: Int = 0 + def eleven: Int = 0 + def twelve: Int = 0 + def twentyOne: Int = 0 + def thirteen: Int = 0 + def twentyTwo: Int = 0 + def thirty: Int = 0 + +inline trait T11 extends T0: + override def eleven: Int = 11 + override def twelve: Int = 11 + override def twentyOne: Int = 11 + override def thirteen: Int = 11 + override def twentyTwo: Int = 11 + override def thirty: Int = 11 + +inline trait T12 extends T0: + override def twelve: Int = 12 + override def twentyOne: Int = 12 + override def thirteen: Int = 12 + override def twentyTwo: Int = 12 + override def thirty: Int = 12 + +inline trait T21 extends T11, T12: + override def twentyOne: Int = 21 + override def thirteen: Int = 21 + override def twentyTwo: Int = 21 + override def thirty: Int = 21 + +inline trait T13 extends T0: + override def thirteen: Int = 13 + override def twentyTwo: Int = 13 + override def thirty: Int = 13 + +inline trait T22 extends T12, T13: + override def twentyTwo: Int = 22 + override def thirty: Int = 22 + +class C extends T21, T22: + override def thirty: Int = 30 diff --git a/tests/run/inline-trait-inheritance-inline-ancestors/normaltraits.scala b/tests/run/inline-trait-inheritance-inline-ancestors/normaltraits.scala new file mode 100644 index 000000000000..f66a85336bff --- /dev/null +++ b/tests/run/inline-trait-inheritance-inline-ancestors/normaltraits.scala @@ -0,0 +1,47 @@ +package normaltraits + +val normalValues: List[Int] = + val c = C() + List(c.zero, c.eleven, c.twelve, c.thirteen, c.twentyOne, c.twentyTwo, c.thirty) + +trait T0: + def zero: Int = 0 + def eleven: Int = 0 + def twelve: Int = 0 + def twentyOne: Int = 0 + def thirteen: Int = 0 + def twentyTwo: Int = 0 + def thirty: Int = 0 + +trait T11 extends T0: + override def eleven: Int = 11 + override def twelve: Int = 11 + override def twentyOne: Int = 11 + override def thirteen: Int = 11 + override def twentyTwo: Int = 11 + override def thirty: Int = 11 + +trait T12 extends T0: + override def twelve: Int = 12 + override def twentyOne: Int = 12 + override def thirteen: Int = 12 + override def twentyTwo: Int = 12 + override def thirty: Int = 12 + +trait T21 extends T11, T12: + override def twentyOne: Int = 21 + override def thirteen: Int = 21 + override def twentyTwo: Int = 21 + override def thirty: Int = 21 + +trait T13 extends T0: + override def thirteen: Int = 13 + override def twentyTwo: Int = 13 + override def thirty: Int = 13 + +trait T22 extends T12, T13: + override def twentyTwo: Int = 22 + override def thirty: Int = 22 + +class C extends T21, T22: + override def thirty: Int = 30 diff --git a/tests/run/inline-trait-inheritance-inline-ancestors/test.scala b/tests/run/inline-trait-inheritance-inline-ancestors/test.scala new file mode 100644 index 000000000000..3cebedee2fbe --- /dev/null +++ b/tests/run/inline-trait-inheritance-inline-ancestors/test.scala @@ -0,0 +1,5 @@ +import normaltraits.normalValues +import inlinetraits.inlineValues + +@main def Test = + assert(normalValues == inlineValues, (normalValues, inlineValues)) diff --git a/tests/run/inline-trait-inheritance-inline-grandparent.check b/tests/run/inline-trait-inheritance-inline-grandparent.check new file mode 100644 index 000000000000..02a3fcae5b4e --- /dev/null +++ b/tests/run/inline-trait-inheritance-inline-grandparent.check @@ -0,0 +1,6 @@ +0 +(Test SimpleC,Hello) + +5678 +(Test C,Hello,9) +5678 diff --git a/tests/run/inline-trait-signature-parameters-val-block.check b/tests/run/inline-trait-signature-parameters-val-block.check new file mode 100644 index 000000000000..063724ea6c43 --- /dev/null +++ b/tests/run/inline-trait-signature-parameters-val-block.check @@ -0,0 +1,4 @@ +I am a B! +1 +1 +1 diff --git a/tests/run/inline-trait-signature-parameters-val-block.scala b/tests/run/inline-trait-signature-parameters-val-block.scala new file mode 100644 index 000000000000..c02f3ceef725 --- /dev/null +++ b/tests/run/inline-trait-signature-parameters-val-block.scala @@ -0,0 +1,10 @@ +inline trait A(val x: Int) + +class B extends A({ println("I am a B!"); 1 }) + +@main() def Test: Unit = { + val b = B() + println(b.x) + println(b.x) + println(b.x) +}