diff options
Diffstat (limited to 'compiler/src/dotty')
19 files changed, 147 insertions, 35 deletions
diff --git a/compiler/src/dotty/tools/dotc/Run.scala b/compiler/src/dotty/tools/dotc/Run.scala index 0f652ff0b..38bf80bad 100644 --- a/compiler/src/dotty/tools/dotc/Run.scala +++ b/compiler/src/dotty/tools/dotc/Run.scala @@ -15,6 +15,7 @@ import reporting.Reporter import transform.TreeChecker import rewrite.Rewrites import java.io.{BufferedWriter, OutputStreamWriter} +import printing.XprintMode import scala.annotation.tailrec import scala.reflect.io.VirtualFile @@ -95,7 +96,7 @@ class Run(comp: Compiler)(implicit ctx: Context) { val unit = ctx.compilationUnit val prevPhase = ctx.phase.prev // can be a mini-phase val squashedPhase = ctx.squashed(prevPhase) - val treeString = unit.tpdTree.show + val treeString = unit.tpdTree.show(ctx.withProperty(XprintMode, Some(()))) ctx.echo(s"result of $unit after $squashedPhase:") diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala index da83d0644..bcda4b92f 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -629,6 +629,28 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => case nil => Nil } + + /** Is this a selection of a member of a structural type that is not a member + * of an underlying class or trait? + */ + def isStructuralTermSelect(tree: Tree)(implicit ctx: Context) = tree match { + case tree: Select => + def hasRefinement(qualtpe: Type): Boolean = qualtpe.dealias match { + case RefinedType(parent, rname, rinfo) => + rname == tree.name || hasRefinement(parent) + case tp: TypeProxy => + hasRefinement(tp.underlying) + case tp: OrType => + hasRefinement(tp.tp1) || hasRefinement(tp.tp2) + case tp: AndType => + hasRefinement(tp.tp1) && hasRefinement(tp.tp2) + case _ => + false + } + !tree.symbol.exists && tree.isTerm && hasRefinement(tree.qualifier.tpe) + case _ => + false + } } object TreeInfo { diff --git a/compiler/src/dotty/tools/dotc/ast/untpd.scala b/compiler/src/dotty/tools/dotc/ast/untpd.scala index f3ffce8f8..37dc32c0e 100644 --- a/compiler/src/dotty/tools/dotc/ast/untpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/untpd.scala @@ -476,7 +476,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { case SymbolLit(str) => cpy.SymbolLit(tree)(str) case InterpolatedString(id, segments) => - cpy.InterpolatedString(tree)(id, transform(segments)) + cpy.InterpolatedString(tree)(id, segments.map(transform(_))) case Function(args, body) => cpy.Function(tree)(transform(args), transform(body)) case InfixOp(left, op, right) => diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 0aeb28d36..7fe6505ff 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -26,6 +26,9 @@ object Definitions { * else without affecting the set of programs that can be compiled. */ val MaxImplementedFunctionArity = 22 + + /** The maximal arity of a function that can be accessed as member of a structural type */ + val MaxStructuralMethodArity = 7 } /** A class defining symbols and types of standard definitions @@ -130,7 +133,7 @@ class Definitions { ClassInfo(ScalaPackageClass.thisType, cls, ObjectType :: parentTraits, decls) } } - newClassSymbol(ScalaPackageClass, name, Trait, completer) + newClassSymbol(ScalaPackageClass, name, Trait | NoInits, completer) } private def newMethod(cls: ClassSymbol, name: TermName, info: Type, flags: FlagSet = EmptyFlags): TermSymbol = @@ -515,6 +518,7 @@ class Definitions { lazy val LanguageModuleRef = ctx.requiredModule("scala.language") def LanguageModuleClass(implicit ctx: Context) = LanguageModuleRef.symbol.moduleClass.asClass lazy val NonLocalReturnControlType: TypeRef = ctx.requiredClassRef("scala.runtime.NonLocalReturnControl") + lazy val SelectableType: TypeRef = ctx.requiredClassRef("scala.Selectable") lazy val ClassTagType = ctx.requiredClassRef("scala.reflect.ClassTag") def ClassTagClass(implicit ctx: Context) = ClassTagType.symbol.asClass @@ -766,6 +770,18 @@ class Definitions { lazy val PhantomClasses = Set[Symbol](AnyClass, AnyValClass, NullClass, NothingClass) + /** Classes that are known not to have an initializer irrespective of + * whether NoInits is set. Note: FunctionXXLClass is in this set + * because if it is compiled by Scala2, it does not get a NoInit flag. + * But since it is introduced only at erasure, there's no chance + * for augmentScala2Traits to do anything on a class that inherits it. So + * it also misses an implementation class, which means that the usual scheme + * of calling a superclass init in the implementation class of a Scala2 + * trait gets screwed up. Therefore, it is mandatory that FunctionXXL + * is treated as a NoInit trait. + */ + lazy val NoInitClasses = PhantomClasses + FunctionXXLClass + def isPolymorphicAfterErasure(sym: Symbol) = (sym eq Any_isInstanceOf) || (sym eq Any_asInstanceOf) diff --git a/compiler/src/dotty/tools/dotc/core/Phases.scala b/compiler/src/dotty/tools/dotc/core/Phases.scala index 7bba88542..44608296a 100644 --- a/compiler/src/dotty/tools/dotc/core/Phases.scala +++ b/compiler/src/dotty/tools/dotc/core/Phases.scala @@ -40,9 +40,6 @@ trait Phases { def atPhaseNotLaterThan[T](limit: Phase)(op: Context => T): T = if (!limit.exists || phase <= limit) op(this) else atPhase(limit)(op) - def atPhaseNotLaterThanTyper[T](op: Context => T): T = - atPhaseNotLaterThan(base.typerPhase)(op) - def isAfterTyper: Boolean = base.isAfterTyper(phase) } diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 716959648..4a9c50dad 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -481,6 +481,7 @@ object StdNames { val sameElements: N = "sameElements" val scala_ : N = "scala" val selectDynamic: N = "selectDynamic" + val selectDynamicMethod: N = "selectDynamicMethod" val selectOverloadedMethod: N = "selectOverloadedMethod" val selectTerm: N = "selectTerm" val selectType: N = "selectType" diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 97a82e80d..5b751ef3c 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -818,7 +818,7 @@ class ClassfileParser( case Some(entry) => val outerName = entry.outerName.stripModuleClassSuffix val owner = classSymbol(outerName) - val result = ctx.atPhaseNotLaterThanTyper { implicit ctx => + val result = ctx.atPhaseNotLaterThan(ctx.typerPhase) { implicit ctx => getMember(owner, innerName.toTypeName) } assert(result ne NoSymbol, diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala index 0dc8d8fea..fb37c9e7d 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala @@ -31,8 +31,10 @@ class TastyPrinter(bytes: Array[Byte])(implicit ctx: Context) { def nameRefToString(ref: NameRef): String = nameToString(tastyName(ref)) def printNames() = - for ((name, idx) <- tastyName.contents.zipWithIndex) - println(f"$idx%4d: " + nameToString(name)) + for ((name, idx) <- tastyName.contents.zipWithIndex) { + val index = "%4d: ".format(idx) + println(index + nameToString(name)) + } def printContents(): Unit = { println("Names:") @@ -47,7 +49,10 @@ class TastyPrinter(bytes: Array[Byte])(implicit ctx: Context) { def unpickle(reader: TastyReader, tastyName: TastyName.Table): Unit = { import reader._ var indent = 0 - def newLine() = print(f"\n ${index(currentAddr) - index(startAddr)}%5d:" + " " * indent) + def newLine() = { + val length = "%5d:".format(index(currentAddr) - index(startAddr)) + print(s"\n $length" + " " * indent) + } def printNat() = print(" " + readNat()) def printName() = { val idx = readNat() diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 51f08a295..ffd594454 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -733,11 +733,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle // no longer necessary. goto(end) setPos(start, tree) - - // This is also done in PostTyper but needs to be redone here - if (!sym.is(SyntheticOrPrivate) && sym.owner.isClass) { - sym.info = Checking.checkNoPrivateLeaks(sym, tree.pos) - } + sym.info = ta.avoidPrivateLeaks(sym, tree.pos) tree } diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 3085ad8fd..7f124563d 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -61,7 +61,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { override def nameString(name: Name): String = name.decode.toString override protected def simpleNameString(sym: Symbol): String = { - val name = sym.originalName + val name = if (ctx.property(XprintMode).isEmpty) sym.originalName else sym.name nameString(if (sym is ExpandedTypeParam) name.asTypeName.unexpandedName else name) } diff --git a/compiler/src/dotty/tools/dotc/printing/package.scala b/compiler/src/dotty/tools/dotc/printing/package.scala index 814eb2ad0..e2c0dda1b 100644 --- a/compiler/src/dotty/tools/dotc/printing/package.scala +++ b/compiler/src/dotty/tools/dotc/printing/package.scala @@ -2,6 +2,7 @@ package dotty.tools.dotc import core.StdNames.nme import parsing.{precedence, minPrec, maxPrec, minInfixPrec} +import util.Property.Key package object printing { @@ -14,4 +15,9 @@ package object printing { val GlobalPrec = parsing.minPrec val TopLevelPrec = parsing.minPrec - 1 + /** A property to indicate whether the compiler is currently doing -Xprint + * + * -Xprint will print `sym.name` instead of `sym.originalName` + */ + val XprintMode = new Key[Unit] } diff --git a/compiler/src/dotty/tools/dotc/transform/Mixin.scala b/compiler/src/dotty/tools/dotc/transform/Mixin.scala index 27cfc835a..fd4370d3e 100644 --- a/compiler/src/dotty/tools/dotc/transform/Mixin.scala +++ b/compiler/src/dotty/tools/dotc/transform/Mixin.scala @@ -175,7 +175,7 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform => case Some(call) => if (defn.PhantomClasses.contains(baseCls)) Nil else call :: Nil case None => - if (baseCls.is(NoInitsTrait) || defn.PhantomClasses.contains(baseCls)) Nil + if (baseCls.is(NoInitsTrait) || defn.NoInitClasses.contains(baseCls)) Nil else { //println(i"synth super call ${baseCls.primaryConstructor}: ${baseCls.primaryConstructor.info}") transformFollowingDeep(superRef(baseCls.primaryConstructor).appliedToNone) :: Nil diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index e7c0df1b9..8dff58dea 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -107,12 +107,6 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran private def transformMemberDef(tree: MemberDef)(implicit ctx: Context): Unit = { val sym = tree.symbol sym.transformAnnotations(transformAnnot) - // Has to be redone in TreeUnpickler - if (!sym.is(SyntheticOrPrivate) && sym.owner.isClass) { - val info1 = Checking.checkNoPrivateLeaks(sym, tree.pos) - if (info1 ne sym.info) - sym.copySymDenotation(info = info1).installAfter(thisTransformer) - } } private def transformSelect(tree: Select, targs: List[Tree])(implicit ctx: Context): Tree = { diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 321c275d7..ca62ed0a9 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -415,6 +415,8 @@ object Checking { /** Verify classes extending AnyVal meet the requirements */ def checkDerivedValueClass(clazz: Symbol, stats: List[Tree])(implicit ctx: Context) = { def checkValueClassMember(stat: Tree) = stat match { + case _: TypeDef if stat.symbol.isClass => + ctx.error(s"value class may not define an inner class", stat.pos) case _: ValDef if !stat.symbol.is(ParamAccessor) => ctx.error(s"value class may not define non-parameter field", stat.pos) case d: DefDef if d.symbol.isConstructor => diff --git a/compiler/src/dotty/tools/dotc/typer/Dynamic.scala b/compiler/src/dotty/tools/dotc/typer/Dynamic.scala index 4039c8b81..000cfd026 100644 --- a/compiler/src/dotty/tools/dotc/typer/Dynamic.scala +++ b/compiler/src/dotty/tools/dotc/typer/Dynamic.scala @@ -7,10 +7,13 @@ import dotty.tools.dotc.ast.tpd import dotty.tools.dotc.ast.untpd import dotty.tools.dotc.core.Constants.Constant import dotty.tools.dotc.core.Contexts.Context -import dotty.tools.dotc.core.Names.Name +import dotty.tools.dotc.core.Names.{Name, TermName} import dotty.tools.dotc.core.StdNames._ import dotty.tools.dotc.core.Types._ import dotty.tools.dotc.core.Decorators._ +import core.Symbols._ +import core.Definitions +import Inferencing._ import ErrorReporting._ object Dynamic { @@ -18,7 +21,10 @@ object Dynamic { name == nme.applyDynamic || name == nme.selectDynamic || name == nme.updateDynamic || name == nme.applyDynamicNamed } -/** Translates selection that does not typecheck according to the scala.Dynamic rules: +/** Handles programmable member selections of `Dynamic` instances and values + * with structural types. Two functionalities: + * + * 1. Translates selection that does not typecheck according to the scala.Dynamic rules: * foo.bar(baz) = quux ~~> foo.selectDynamic(bar).update(baz, quux) * foo.bar = baz ~~> foo.updateDynamic("bar")(baz) * foo.bar(x = bazX, y = bazY, baz, ...) ~~> foo.applyDynamicNamed("bar")(("x", bazX), ("y", bazY), ("", baz), ...) @@ -26,6 +32,10 @@ object Dynamic { * foo.bar ~~> foo.selectDynamic(bar) * * The first matching rule of is applied. + * + * 2. Translates member selections on structural types to calls of `selectDynamic` + * or `selectDynamicMethod` on a `Selectable` instance. @See handleStructural. + * */ trait Dynamic { self: Typer with Applications => import Dynamic._ @@ -100,4 +110,56 @@ trait Dynamic { self: Typer with Applications => else untpd.TypeApply(select, targs) untpd.Apply(selectWithTypes, Literal(Constant(name.toString))) } + + /** Handle reflection-based dispatch for members of structural types. + * Given `x.a`, where `x` is of (widened) type `T` and `x.a` is of type `U`: + * + * If `U` is a value type, map `x.a` to the equivalent of: + * + * (x: Selectable).selectDynamic(x, "a").asInstanceOf[U] + * + * If `U` is a method type (T1,...,Tn)R, map `x.a` to the equivalent of: + * + * (x: Selectable).selectDynamicMethod("a", CT1, ..., CTn).asInstanceOf[(T1,...,Tn) => R] + * + * where CT1,...,CTn are the class tags representing the erasure of T1,...,Tn. + * + * It's an error if U is neither a value nor a method type, or a dependent method + * type, or of too large arity (limit is Definitions.MaxStructuralMethodArity). + */ + def handleStructural(tree: Tree)(implicit ctx: Context): Tree = { + val Select(qual, name) = tree + + def structuralCall(selectorName: TermName, formals: List[Tree]) = { + val selectable = adapt(qual, defn.SelectableType) + val scall = untpd.Apply( + untpd.TypedSplice(selectable.select(selectorName)), + (Literal(Constant(name.toString)) :: formals).map(untpd.TypedSplice(_))) + typed(scall) + } + + def fail(reason: String) = + errorTree(tree, em"Structural access not allowed on method $name because it $reason") + + tree.tpe.widen match { + case tpe: MethodType => + if (tpe.isDependent) + fail(i"has a dependent method type") + else if (tpe.paramNames.length > Definitions.MaxStructuralMethodArity) + fail(i"""takes too many parameters. + |Structural types only support methods taking up to ${Definitions.MaxStructuralMethodArity} arguments""") + else { + def issueError(msgFn: String => String): Unit = ctx.error(msgFn(""), tree.pos) + val ctags = tpe.paramTypes.map(pt => + inferImplicitArg(defn.ClassTagType.appliedTo(pt :: Nil), issueError, tree.pos.endPos)) + structuralCall(nme.selectDynamicMethod, ctags).asInstance(tpe.toFunctionType()) + } + case tpe: ValueType => + structuralCall(nme.selectDynamic, Nil).asInstance(tpe) + case tpe: PolyType => + fail("is polymorphic") + case tpe => + fail(i"has an unsupported type: $tpe") + } + } } diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index 09487570d..cfc0003c6 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -327,7 +327,7 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { (tp.paramNames, tp.paramTypes, argss.head).zipped.foreach { (name, paramtp, arg) => def isByName = paramtp.dealias.isInstanceOf[ExprType] paramBinding(name) = arg.tpe.stripAnnots.stripTypeVar match { - case argtpe: SingletonType if isByName || isIdempotentExpr(arg) => argtpe + case argtpe: SingletonType if isIdempotentExpr(arg) => argtpe case argtpe => val inlineFlag = if (paramtp.hasAnnotation(defn.InlineParamAnnot)) Inline else EmptyFlags val (bindingFlags, bindingType) = diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 068ef3e4b..1672512a7 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -498,7 +498,9 @@ class Namer { typer: Typer => } for (mdef @ ModuleDef(name, _) <- stats if !mdef.mods.is(Flags.Package)) { val typName = name.toTypeName - val Thicket(vdef :: (mcls @ TypeDef(_, impl: Template)) :: Nil) = mdef.attachment(ExpandedTree) + // Expansion of object is a flattened thicket with the first two elements being: + // module val :: module class :: rest + val Thicket(vdef :: (mcls @ TypeDef(_, impl: Template)) :: rest) = expanded(mdef) moduleDef(typName) = mcls classDef get name.toTypeName match { case Some(cdef) => @@ -506,7 +508,7 @@ class Namer { typer: Typer => case Thicket(cls :: mval :: TypeDef(_, compimpl: Template) :: crest) => val mcls1 = cpy.TypeDef(mcls)( rhs = cpy.Template(impl)(body = compimpl.body ++ impl.body)) - mdef.putAttachment(ExpandedTree, Thicket(vdef :: mcls1 :: Nil)) + mdef.putAttachment(ExpandedTree, Thicket(vdef :: mcls1 :: rest)) moduleDef(typName) = mcls1 cdef.putAttachment(ExpandedTree, Thicket(cls :: crest)) case _ => @@ -668,13 +670,15 @@ class Namer { typer: Typer => * to pick up the context at the point where the completer was created. */ def completeInCreationContext(denot: SymDenotation): Unit = { + val sym = denot.symbol original match { - case original: MemberDef => addAnnotations(denot.symbol, original) + case original: MemberDef => addAnnotations(sym, original) case _ => } addInlineInfo(denot) - denot.info = typeSig(denot.symbol) - Checking.checkWellFormed(denot.symbol) + denot.info = typeSig(sym) + Checking.checkWellFormed(sym) + denot.info = avoidPrivateLeaks(sym, sym.pos) } } @@ -854,6 +858,7 @@ class Namer { typer: Typer => if (isDerivedValueClass(cls)) cls.setFlag(Final) cls.setApplicableFlags( (NoInitsInterface /: impl.body)((fs, stat) => fs & defKind(stat))) + cls.info = avoidPrivateLeaks(cls, cls.pos) } } diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 5c07b7bcf..53ce5555b 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -132,6 +132,11 @@ trait TypeAssigner { def avoidingType(expr: Tree, bindings: List[Tree])(implicit ctx: Context): Type = avoid(expr.tpe, localSyms(bindings).filter(_.isTerm)) + def avoidPrivateLeaks(sym: Symbol, pos: Position)(implicit ctx: Context): Type = + if (!sym.is(SyntheticOrPrivate) && sym.owner.isClass) + Checking.checkNoPrivateLeaks(sym, pos) + else sym.info + def seqToRepeated(tree: Tree)(implicit ctx: Context): Tree = Typed(tree, TypeTree(tree.tpe.widen.translateParameterized(defn.SeqClass, defn.RepeatedParamClass))) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index d05a0aaa7..59df98a93 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1040,9 +1040,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit typr.println(s"adding refinement $refinement") checkRefinementNonCyclic(refinement, refineCls, seen) val rsym = refinement.symbol - if (rsym.is(Method) && rsym.allOverriddenSymbols.isEmpty) - ctx.error(i"refinement $rsym without matching type in parent $tpt1", refinement.pos) - } + if (rsym.info.isInstanceOf[PolyType] && rsym.allOverriddenSymbols.isEmpty) + ctx.error(i"polymorphic refinement $rsym without matching type in parent $tpt1 is no longer allowed", refinement.pos) } assignType(cpy.RefinedTypeTree(tree)(tpt1, refinements1), tpt1, refinements1, refineCls) } @@ -2067,7 +2066,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit adaptInterpolated(tree.appliedToTypeTrees(typeArgs), pt, original)) } case wtp => - pt match { + if (isStructuralTermSelect(tree)) adapt(handleStructural(tree), pt) + else pt match { case pt: FunProto => adaptToArgs(wtp, pt) case pt: PolyProto => |