Skip to content

Commit 2217a4e

Browse files
committed
Merge pull request #1072 from dotty-staging/change-isVolatile-2
Change is volatile 2
2 parents ea407f1 + 1230158 commit 2217a4e

29 files changed

+957
-108
lines changed

docs/SyntaxSummary.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ grammar.
103103
RefinedType ::= WithType {[nl] Refinement} RefinedTypeTree(t, ds)
104104
WithType ::= AnnotType {`with' AnnotType} (deprecated)
105105
AnnotType ::= SimpleType {Annotation} Annotated(t, annot)
106-
SimpleType ::= SimpleType TypeArgs AppliedTypeTree(t, args)
106+
SimpleType ::= SimpleType (TypeArgs | NamedTypeArgs) AppliedTypeTree(t, args)
107107
| SimpleType `#' id SelectFromTypeTree(t, name)
108108
| StableId
109109
| Path `.' `type' SingletonTypeTree(p)
@@ -118,6 +118,8 @@ grammar.
118118
ParamType ::= [`=>'] ParamValueType
119119
ParamValueType ::= Type [`*'] PostfixOp(t, "*")
120120
TypeArgs ::= `[' ArgTypes `]' ts
121+
NamedTypeArg ::= id `=' ArgType NamedArg(id, t)
122+
NamedTypeArgs ::= `[' NamedTypeArg {`,' NamedTypeArg} `]' nts
121123
Refinement ::= `{' [Dcl] {semi [Dcl]} `}' ds
122124
TypeBounds ::= [`>:' Type] [`<: Type] | INT TypeBoundsTree(lo, hi)
123125
TypeParamBounds ::= TypeBounds {`<%' Type} {`:' Type} ContextBounds(typeBounds, tps)
@@ -160,7 +162,7 @@ grammar.
160162
| `_'
161163
| `(' ExprsInParens `)' Parens(exprs)
162164
| SimpleExpr `.' id Select(expr, id)
163-
| SimpleExpr TypeArgs TypeApply(expr, args)
165+
| SimpleExpr (TypeArgs | NamedTypeArgs) TypeApply(expr, args)
164166
| SimpleExpr1 ArgumentExprs Apply(expr, args)
165167
| XmlExpr
166168
ExprsInParens ::= ExprInParens {`,' ExprInParens}

src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ object desugar {
6767
val defctx = ctx.outersIterator.dropWhile(_.scope eq ctx.scope).next
6868
var local = defctx.denotNamed(tp.name).suchThat(_ is ParamOrAccessor).symbol
6969
if (local.exists) (defctx.owner.thisType select local).dealias
70-
else throw new Error(s"no matching symbol for ${sym.showLocated} in ${defctx.owner} / ${defctx.effectiveScope}")
70+
else throw new Error(s"no matching symbol for ${tp.symbol.showLocated} in ${defctx.owner} / ${defctx.effectiveScope}")
7171
case _ =>
7272
mapOver(tp)
7373
}

src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,10 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
215215
case _ => false
216216
}
217217

218+
/** Does this list contain a named argument tree? */
219+
def hasNamedArg(args: List[Any]) = args exists isNamedArg
220+
val isNamedArg = (arg: Any) => arg.isInstanceOf[Trees.NamedArg[_]]
221+
218222
/** Is this pattern node a catch-all (wildcard or variable) pattern? */
219223
def isDefaultCase(cdef: CaseDef) = cdef match {
220224
case CaseDef(pat, EmptyTree, _) => isWildcardArg(pat)

src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
6767
def Typed(expr: Tree, tpt: Tree)(implicit ctx: Context): Typed =
6868
ta.assignType(untpd.Typed(expr, tpt), tpt)
6969

70-
def NamedArg(name: Name, arg: Tree)(implicit ctx: Context) =
70+
def NamedArg(name: Name, arg: Tree)(implicit ctx: Context): NamedArg =
7171
ta.assignType(untpd.NamedArg(name, arg), arg)
7272

7373
def Assign(lhs: Tree, rhs: Tree)(implicit ctx: Context): Assign =

src/dotty/tools/dotc/core/CheckRealizable.scala

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -63,23 +63,6 @@ class CheckRealizable(implicit ctx: Context) {
6363
*/
6464
private def isLateInitialized(sym: Symbol) = sym.is(Lazy, butNot = Module)
6565

66-
/** Is this type a path with some part that is initialized on use?
67-
*/
68-
private def isLateInitialized(tp: Type): Boolean = tp.dealias match {
69-
case tp: TermRef =>
70-
isLateInitialized(tp.symbol) || isLateInitialized(tp.prefix)
71-
case _: SingletonType | NoPrefix =>
72-
false
73-
case tp: TypeRef =>
74-
true
75-
case tp: TypeProxy =>
76-
isLateInitialized(tp.underlying)
77-
case tp: AndOrType =>
78-
isLateInitialized(tp.tp1) || isLateInitialized(tp.tp2)
79-
case _ =>
80-
true
81-
}
82-
8366
/** The realizability status of given type `tp`*/
8467
def realizability(tp: Type): Realizability = tp.dealias match {
8568
case tp: TermRef =>
@@ -121,13 +104,17 @@ class CheckRealizable(implicit ctx: Context) {
121104
}
122105
}
123106

124-
/** `Realizable` if `tp` all of `tp`'s non-struct fields have realizable types,
107+
/** `Realizable` if all of `tp`'s non-struct fields have realizable types,
125108
* a `HasProblemField` instance pointing to a bad field otherwise.
126109
*/
127110
private def memberRealizability(tp: Type) = {
128111
def checkField(sofar: Realizability, fld: SingleDenotation): Realizability =
129112
sofar andAlso {
130113
if (checkedFields.contains(fld.symbol) || fld.symbol.is(Private | Mutable | Lazy))
114+
// if field is private it cannot be part of a visible path
115+
// if field is mutable it cannot be part of a path
116+
// if field is lazy it does not need to be initialized when the owning object is
117+
// so in all cases the field does not influence realizability of the enclosing object.
131118
Realizable
132119
else {
133120
checkedFields += fld.symbol

src/dotty/tools/dotc/core/Flags.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,9 @@ object Flags {
594594
/** A private parameter accessor */
595595
final val PrivateParamAccessor = allOf(Private, ParamAccessor)
596596

597+
/** A type parameter introduced with [type ... ] */
598+
final val NamedTypeParam = allOf(TypeParam, ParamAccessor)
599+
597600
/** A local parameter */
598601
final val ParamAndLocal = allOf(Param, Local)
599602

src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1516,6 +1516,20 @@ object SymDenotations {
15161516
if (myMemberCache != null) myMemberCache invalidate sym.name
15171517
}
15181518

1519+
/** Make sure the type parameters of this class are `tparams`, reorder definitions
1520+
* in scope if necessary.
1521+
* @pre All type parameters in `tparams` are entered in class scope `info.decls`.
1522+
*/
1523+
def updateTypeParams(tparams: List[Symbol])(implicit ctx: Context): Unit =
1524+
if (!typeParams.corresponds(tparams)(_.name == _.name)) {
1525+
val decls = info.decls
1526+
val decls1 = newScope
1527+
for (tparam <- tparams) decls1.enter(decls.lookup(tparam.name))
1528+
for (sym <- decls) if (!typeParams.contains(sym)) decls1.enter(sym)
1529+
info = classInfo.derivedClassInfo(decls = decls1)
1530+
myTypeParams = null
1531+
}
1532+
15191533
/** All members of this class that have the given name.
15201534
* The elements of the returned pre-denotation all
15211535
* have existing symbols.

src/dotty/tools/dotc/core/TypeApplications.scala

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,7 @@ class TypeApplications(val self: Type) extends AnyVal {
244244
else tsym.infoOrCompleter match {
245245
case completer: TypeParamsCompleter =>
246246
val tparams = completer.completerTypeParams(tsym)
247-
if (tsym.isClass) tparams
248-
else defn.LambdaTrait(tparams.map(_.variance)).typeParams
247+
defn.LambdaTrait(tparams.map(_.variance)).typeParams
249248
case _ =>
250249
if (!tsym.isCompleting || tsym.isAliasType) tsym.info.typeParams
251250
else
@@ -548,9 +547,12 @@ class TypeApplications(val self: Type) extends AnyVal {
548547
self
549548
case _ =>
550549
val v = tparam.variance
550+
/* Not neeeded.
551551
if (v > 0 && !(tparam is Local) && !(tparam is ExpandedTypeParam)) TypeBounds.upper(self)
552552
else if (v < 0 && !(tparam is Local) && !(tparam is ExpandedTypeParam)) TypeBounds.lower(self)
553-
else TypeAlias(self, v)
553+
else
554+
*/
555+
TypeAlias(self, v)
554556
}
555557

556558
/** The type arguments of this type's base type instance wrt. `base`.

src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
371371
case _ =>
372372
compareRefinedSlow ||
373373
fourthTry(tp1, tp2) ||
374-
compareHkLambda(tp2, tp1, inOrder = false)
374+
compareHkLambda(tp2, tp1, inOrder = false) ||
375+
compareAliasedRefined(tp2, tp1, inOrder = false)
375376
}
376377
else // fast path, in particular for refinements resulting from parameterization.
377378
isSubType(tp1, skipped2) &&
@@ -491,7 +492,9 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
491492
}
492493
isNewSubType(tp1.underlying.widenExpr, tp2) || comparePaths
493494
case tp1: RefinedType =>
494-
isNewSubType(tp1.parent, tp2) || compareHkLambda(tp1, tp2, inOrder = true)
495+
isNewSubType(tp1.parent, tp2) ||
496+
compareHkLambda(tp1, tp2, inOrder = true) ||
497+
compareAliasedRefined(tp1, tp2, inOrder = true)
495498
case AndType(tp11, tp12) =>
496499
// Rewrite (T111 | T112) & T12 <: T2 to (T111 & T12) <: T2 and (T112 | T12) <: T2
497500
// and analogously for T11 & (T121 | T122) & T12 <: T2
@@ -614,6 +617,35 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
614617
false
615618
}
616619

620+
/** Say we are comparing a refined type `P{type M = U}` or `P{type M >: L <: U}`.
621+
* If P#M refers to a BaseTypeArg aliased to some other typeref P#N,
622+
* do the same comparison with `P{type N = U}` or `P{type N >: L <: U}`, respectively.
623+
* This allows to handle situations involving named type params like this one:
624+
*
625+
* trait Lambda[type Elem]
626+
* trait Lst[T] extends Lambda[T]
627+
*
628+
* compareAliasedRefined is necessary so we establish that
629+
*
630+
* Lst[Int] = Lst[Elem = Int]
631+
*/
632+
private def compareAliasedRefined(rt: RefinedType, other: Type, inOrder: Boolean) = {
633+
val mbr = refinedSymbol(rt)
634+
mbr.is(BaseTypeArg) && {
635+
mbr.info match {
636+
case TypeAlias(TypeRef(_, aliasName)) =>
637+
val rt1 = rt.derivedRefinedType(rt.parent, aliasName, rt.refinedInfo)
638+
subtyping.println(i"rewiring $rt to $rt1 in comparison with $other")
639+
if (inOrder) isSubType(rt1, other) else isSubType(other, rt1)
640+
case _ =>
641+
false
642+
}
643+
}
644+
}
645+
646+
/** The symbol referred to in the refinement of `rt` */
647+
private def refinedSymbol(rt: RefinedType) = rt.parent.member(rt.refinedName).symbol
648+
617649
/** Returns true iff either `tp11 <:< tp21` or `tp12 <:< tp22`, trying at the same time
618650
* to keep the constraint as wide as possible. Specifically, if
619651
*
@@ -742,11 +774,14 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
742774
/** A type has been covered previously in subtype checking if it
743775
* is some combination of TypeRefs that point to classes, where the
744776
* combiners are RefinedTypes, AndTypes or AnnotatedTypes.
777+
* One exception: Refinements referring to basetype args are never considered
778+
* to be already covered. This is necessary because such refined types might
779+
* still need to be compared with a compareAliasRefined.
745780
*/
746781
private def isCovered(tp: Type): Boolean = tp.dealias.stripTypeVar match {
747782
case tp: TypeRef => tp.symbol.isClass && tp.symbol != NothingClass && tp.symbol != NullClass
748783
case tp: ProtoType => false
749-
case tp: RefinedType => isCovered(tp.parent)
784+
case tp: RefinedType => isCovered(tp.parent) && !refinedSymbol(tp).is(BaseTypeArg)
750785
case tp: AnnotatedType => isCovered(tp.underlying)
751786
case AndType(tp1, tp2) => isCovered(tp1) && isCovered(tp2)
752787
case _ => false

src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -444,10 +444,16 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
444444
case tp: TypeRef =>
445445
tp
446446
case tp @ RefinedType(tp1, name: TypeName) =>
447-
val prevInfo = refinements(name)
448-
refinements = refinements.updated(name,
449-
if (prevInfo == null) tp.refinedInfo else prevInfo & tp.refinedInfo)
450-
formals = formals.updated(name, tp1.typeParamNamed(name))
447+
tp.refinedInfo match {
448+
case TypeAlias(TypeRef(pre, name1)) if name1 == name && (pre =:= cls.thisType) =>
449+
// Don't record refinements of the form X = this.X (These can arise using named parameters).
450+
typr.println(s"dropping refinement $tp")
451+
case _ =>
452+
val prevInfo = refinements(name)
453+
refinements = refinements.updated(name,
454+
if (prevInfo == null) tp.refinedInfo else prevInfo & tp.refinedInfo)
455+
formals = formals.updated(name, tp1.typeParamNamed(name))
456+
}
451457
normalizeToRef(tp1)
452458
case ErrorType =>
453459
defn.AnyType

src/dotty/tools/dotc/core/Types.scala

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,13 @@ object Types {
485485
}
486486
def goThis(tp: ThisType) = {
487487
val d = go(tp.underlying)
488-
if (d.exists) d
488+
if (d.exists)
489+
if ((pre eq tp) && d.symbol.is(NamedTypeParam) && (d.symbol.owner eq tp.cls))
490+
// If we look for a named type parameter `P` in `C.this.P`, looking up
491+
// the fully applied self type of `C` will give as an info the alias type
492+
// `P = this.P`. We need to return a denotation with the underlying bounds instead.
493+
d.symbol.denot
494+
else d
489495
else
490496
// There is a special case to handle:
491497
// trait Super { this: Sub => private class Inner {} println(this.Inner) }
@@ -854,11 +860,9 @@ object Types {
854860
else NoType
855861
case tp: AnnotatedType => tp.underlying.underlyingClassRef(refinementOK)
856862
case tp: RefinedType =>
857-
if (refinementOK) tp.underlying.underlyingClassRef(refinementOK)
858-
else {
859-
val tycon = tp.withoutArgs(tp.argInfos)
860-
if (tycon eq tp) NoType else tycon.underlyingClassRef(refinementOK)
861-
}
863+
def isParamName = tp.classSymbol.typeParams.exists(_.name == tp.refinedName)
864+
if (refinementOK || isParamName) tp.underlying.underlyingClassRef(refinementOK)
865+
else NoType
862866
case _ => NoType
863867
}
864868

src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -132,18 +132,10 @@ object Scala2Unpickler {
132132
} else {
133133
registerCompanionPair(scalacCompanion, denot.classSymbol)
134134
}
135-
val declsTypeParams = denot.typeParams
136-
val declsInRightOrder =
137-
if (declsTypeParams.corresponds(tparams)(_.name == _.name)) decls
138-
else { // create new scope with type parameters in right order
139-
val decls1 = newScope
140-
for (tparam <- tparams) decls1.enter(decls.lookup(tparam.name))
141-
for (sym <- decls) if (!declsTypeParams.contains(sym)) decls1.enter(sym)
142-
decls1
143-
}
144135

145-
denot.info = ClassInfo( // final info
146-
denot.owner.thisType, denot.classSymbol, parentRefs, declsInRightOrder, ost)
136+
denot.info = ClassInfo( // final info, except possibly for typeparams ordering
137+
denot.owner.thisType, denot.classSymbol, parentRefs, decls, ost)
138+
denot.updateTypeParams(tparams)
147139
}
148140
}
149141

src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,7 @@ object Parsers {
740740

741741
private def simpleTypeRest(t: Tree): Tree = in.token match {
742742
case HASH => simpleTypeRest(typeProjection(t))
743-
case LBRACKET => simpleTypeRest(atPos(t.pos.start) { AppliedTypeTree(t, typeArgs()) })
743+
case LBRACKET => simpleTypeRest(atPos(t.pos.start) { AppliedTypeTree(t, typeArgs(namedOK = true)) })
744744
case _ => t
745745
}
746746

@@ -759,9 +759,38 @@ object Parsers {
759759
}
760760
else typ()
761761

762+
/** NamedTypeArg ::= id `=' ArgType
763+
*/
764+
val namedTypeArg = () => {
765+
val name = ident()
766+
accept(EQUALS)
767+
NamedArg(name.toTypeName, argType())
768+
}
769+
762770
/** ArgTypes ::= ArgType {`,' ArgType}
771+
* NamedTypeArg {`,' NamedTypeArg}
763772
*/
764-
def argTypes() = commaSeparated(argType)
773+
def argTypes(namedOK: Boolean = false) = {
774+
def otherArgs(first: Tree, arg: () => Tree): List[Tree] = {
775+
val rest =
776+
if (in.token == COMMA) {
777+
in.nextToken()
778+
commaSeparated(arg)
779+
}
780+
else Nil
781+
first :: rest
782+
}
783+
if (namedOK && in.token == IDENTIFIER)
784+
argType() match {
785+
case Ident(name) if in.token == EQUALS =>
786+
in.nextToken()
787+
otherArgs(NamedArg(name, argType()), namedTypeArg)
788+
case firstArg =>
789+
if (in.token == EQUALS) println(s"??? $firstArg")
790+
otherArgs(firstArg, argType)
791+
}
792+
else commaSeparated(argType)
793+
}
765794

766795
/** FunArgType ::= ArgType | `=>' ArgType
767796
*/
@@ -785,9 +814,10 @@ object Parsers {
785814
} else t
786815
}
787816

788-
/** TypeArgs ::= `[' ArgType {`,' ArgType} `]'
789-
*/
790-
def typeArgs(): List[Tree] = inBrackets(argTypes())
817+
/** TypeArgs ::= `[' ArgType {`,' ArgType} `]'
818+
* NamedTypeArgs ::= `[' NamedTypeArg {`,' NamedTypeArg} `]'
819+
*/
820+
def typeArgs(namedOK: Boolean = false): List[Tree] = inBrackets(argTypes(namedOK))
791821

792822
/** Refinement ::= `{' RefineStatSeq `}'
793823
*/
@@ -1045,7 +1075,7 @@ object Parsers {
10451075
* | Path
10461076
* | `(' [ExprsInParens] `)'
10471077
* | SimpleExpr `.' Id
1048-
* | SimpleExpr TypeArgs
1078+
* | SimpleExpr (TypeArgs | NamedTypeArgs)
10491079
* | SimpleExpr1 ArgumentExprs
10501080
*/
10511081
def simpleExpr(): Tree = {
@@ -1094,7 +1124,7 @@ object Parsers {
10941124
in.nextToken()
10951125
simpleExprRest(selector(t), canApply = true)
10961126
case LBRACKET =>
1097-
val tapp = atPos(t.pos.start, in.offset) { TypeApply(t, typeArgs()) }
1127+
val tapp = atPos(t.pos.start, in.offset) { TypeApply(t, typeArgs(namedOK = true)) }
10981128
simpleExprRest(tapp, canApply = true)
10991129
case LPAREN | LBRACE if canApply =>
11001130
val app = atPos(t.pos.start, in.offset) { Apply(t, argumentExprs()) }
@@ -1493,7 +1523,7 @@ object Parsers {
14931523
atPos(modStart, in.offset) {
14941524
if (in.token == TYPE) {
14951525
in.nextToken()
1496-
mods | Param
1526+
mods | Param | ParamAccessor
14971527
} else {
14981528
if (mods.hasFlags) syntaxError("`type' expected")
14991529
mods | Param | PrivateLocal

src/dotty/tools/dotc/transform/Constructors.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ class Constructors extends MiniPhaseTransform with SymTransformer { thisTransfor
246246

247247
// Drop accessors that are not retained from class scope
248248
if (dropped.nonEmpty) {
249-
val clsInfo = cls.classInfo // TODO investigate: expand clsInfo to cls.info => dotty type error
249+
val clsInfo = cls.classInfo
250250
cls.copy(
251251
info = clsInfo.derivedClassInfo(
252252
decls = clsInfo.decls.filteredScope(!dropped.contains(_))))

0 commit comments

Comments
 (0)