Skip to content

Commit 39ca54f

Browse files
oderskysmarter
authored andcommitted
Check bounds everywhere
Previously, bounds of a TypeDef tree were not checked. We now make sure bounds are checked everywhere in PostTyper. The previous partial check in Applications gets removed (it was not complete even for TypeApplications because sometimes bounds were not yet known when the test was performed.)
1 parent c0b545b commit 39ca54f

File tree

3 files changed

+35
-29
lines changed

3 files changed

+35
-29
lines changed

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

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
6868
// TODO fill in
6969
}
7070

71-
/** Check bounds of AppliedTypeTrees and TypeApplys.
71+
/** Check bounds of AppliedTypeTrees.
7272
* Replace type trees with TypeTree nodes.
7373
* Replace constant expressions with Literal nodes.
7474
* Note: Demanding idempotency instead of purity in literalize is strictly speaking too loose.
@@ -97,29 +97,17 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
9797
* Revisit this issue once we have implemented `inline`. Then we can demand
9898
* purity of the prefix unless the selection goes to an inline val.
9999
*/
100-
private def normalizeTree(tree: Tree)(implicit ctx: Context): Tree = {
101-
def literalize(tp: Type): Tree = tp.widenTermRefExpr match {
102-
case ConstantType(value) if isIdempotentExpr(tree) => Literal(value)
103-
case _ => tree
104-
}
105-
def norm(tree: Tree) =
106-
if (tree.isType) TypeTree(tree.tpe).withPos(tree.pos)
107-
else literalize(tree.tpe)
108-
tree match {
109-
case tree: TypeTree =>
110-
tree
111-
case AppliedTypeTree(tycon, args) =>
112-
val tparams = tycon.tpe.typeSymbol.typeParams
113-
val bounds = tparams.map(tparam =>
114-
tparam.info.asSeenFrom(tycon.tpe.normalizedPrefix, tparam.owner.owner).bounds)
115-
Checking.checkBounds(args, bounds, _.substDealias(tparams, _))
116-
norm(tree)
117-
case TypeApply(fn, args) =>
118-
Checking.checkBounds(args, fn.tpe.widen.asInstanceOf[PolyType])
119-
norm(tree)
120-
case _ =>
121-
norm(tree)
122-
}
100+
private def normalizeTree(tree: Tree)(implicit ctx: Context): Tree = tree match {
101+
case tree: TypeTree => tree
102+
case _ =>
103+
if (tree.isType) {
104+
Checking.boundsChecker.traverse(tree)
105+
TypeTree(tree.tpe).withPos(tree.pos)
106+
}
107+
else tree.tpe.widenTermRefExpr match {
108+
case ConstantType(value) if isIdempotentExpr(tree) => Literal(value)
109+
case _ => tree
110+
}
123111
}
124112

125113
class PostTyperTransformer extends Transformer {
@@ -161,10 +149,16 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
161149
}
162150
case tree: Select =>
163151
transformSelect(paramFwd.adaptRef(tree), Nil)
164-
case tree @ TypeApply(sel: Select, args) =>
165-
val args1 = transform(args)
166-
val sel1 = transformSelect(sel, args1)
167-
if (superAcc.isProtectedAccessor(sel1)) sel1 else cpy.TypeApply(tree)(sel1, args1)
152+
case tree @ TypeApply(fn, args) =>
153+
Checking.checkBounds(args, fn.tpe.widen.asInstanceOf[PolyType])
154+
fn match {
155+
case sel: Select =>
156+
val args1 = transform(args)
157+
val sel1 = transformSelect(sel, args1)
158+
if (superAcc.isProtectedAccessor(sel1)) sel1 else cpy.TypeApply(tree)(sel1, args1)
159+
case _ =>
160+
super.transform(tree)
161+
}
168162
case tree @ Assign(sel: Select, _) =>
169163
superAcc.transformAssign(super.transform(tree))
170164
case tree: Template =>
@@ -186,6 +180,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
186180
val tree1 =
187181
if (sym.isClass) tree
188182
else {
183+
Checking.boundsChecker.traverse(tree.rhs)
189184
cpy.TypeDef(tree)(rhs = TypeTree(tree.symbol.info))
190185
}
191186
super.transform(tree1)

src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -607,7 +607,6 @@ trait Applications extends Compatibility { self: Typer =>
607607
case pt: PolyType =>
608608
if (typedArgs.length <= pt.paramBounds.length)
609609
typedArgs = typedArgs.zipWithConserve(pt.paramBounds)(adaptTypeArg)
610-
Checking.checkBounds(typedArgs, pt)
611610
case _ =>
612611
}
613612
assignType(cpy.TypeApply(tree)(typedFn, typedArgs), typedFn, typedArgs)

src/dotty/tools/dotc/typer/Checking.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,18 @@ object Checking {
4848
def checkBounds(args: List[tpd.Tree], poly: PolyType)(implicit ctx: Context): Unit =
4949
checkBounds(args, poly.paramBounds, _.substParams(poly, _))
5050

51+
/** Check all AppliedTypeTree nodes in this tree for legal bounds */
52+
val boundsChecker = new TreeTraverser {
53+
def traverse(tree: Tree)(implicit ctx: Context) = tree match {
54+
case AppliedTypeTree(tycon, args) =>
55+
val tparams = tycon.tpe.typeSymbol.typeParams
56+
val bounds = tparams.map(tparam =>
57+
tparam.info.asSeenFrom(tycon.tpe.normalizedPrefix, tparam.owner.owner).bounds)
58+
checkBounds(args, bounds, _.substDealias(tparams, _))
59+
case _ => traverseChildren(tree)
60+
}
61+
}
62+
5163
/** Check that `tp` refers to a nonAbstract class
5264
* and that the instance conforms to the self type of the created class.
5365
*/

0 commit comments

Comments
 (0)