Skip to content

Fix #9029: Change whitebox macro syntax #9048

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ class TreeUnpickler(reader: TastyReader,
if (tag == TYPEDEF || tag == TYPEPARAM) name = name.toTypeName
skipParams()
val ttag = nextUnsharedTag
val isAbsType = isAbstractType(ttag)
val isAbsType = name.isTypeName && isAbstractType(ttag)
val isClass = ttag == TEMPLATE
val templateStart = currentAddr
skipTree() // tpt
Expand Down Expand Up @@ -812,9 +812,12 @@ class TreeUnpickler(reader: TastyReader,
val vparamss = readParamss(localCtx)
val tpt = readTpt()(localCtx)
val typeParams = tparams.map(_.symbol)
val valueParamss = ctx.normalizeIfConstructor(
vparamss.nestedMap(_.symbol), name == nme.CONSTRUCTOR)
val resType = ctx.effectiveResultType(sym, typeParams, tpt.tpe)
val isConstructor = name == nme.CONSTRUCTOR
val valueParamss =
ctx.normalizeIfConstructor(vparamss.nestedMap(_.symbol), isConstructor)
val resType =
if isConstructor then sym.constructorResultType(typeParams)
else tpt.tpe.bounds.hi
sym.info = ctx.methodType(typeParams, valueParamss, resType)
DefDef(tparams, vparamss, tpt)
case VALDEF =>
Expand Down
60 changes: 30 additions & 30 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ object Parsers {

import ast.untpd._

val AllowOldWhiteboxSyntax = true

case class OpInfo(operand: Tree, operator: Ident, offset: Offset)

class ParensCounters {
Expand Down Expand Up @@ -1774,16 +1772,21 @@ object Parsers {
Nil
}

def typedOpt(): Tree = {
if (in.token == COLONEOL) in.token = COLON
// a hack to allow
//
// def f():
// T
//
if (in.token == COLON) { in.nextToken(); toplevelTyp() }
def typedOpt(typ: => Tree) =
if (in.token == COLON) { in.nextToken(); typ }
else TypeTree().withSpan(Span(in.lastOffset))
}

/** ResultType ::= [‘_’ ‘<:] Type */
def resultType(mods: Modifiers): Tree =
if in.token == USCORE && in.lookahead.token == SUBTYPE then
atSpan(in.offset) {
in.nextToken()
if !mods.is(Inline) then
syntaxError(em"upper bound is only permitted for inline definitions")
in.nextToken()
TypeBoundsTree(EmptyTree, toplevelTyp())
}
else toplevelTyp()

def typeDependingOn(location: Location): Tree =
if location.inParens then typ()
Expand Down Expand Up @@ -2138,7 +2141,9 @@ object Parsers {
/** Binding ::= (id | `_') [`:' Type]
*/
def binding(mods: Modifiers): Tree =
atSpan(in.offset) { makeParameter(bindingName(), typedOpt(), mods) }
atSpan(in.offset) {
makeParameter(bindingName(), typedOpt(toplevelTyp()), mods)
}

def bindingName(): TermName =
if (in.token == USCORE) {
Expand Down Expand Up @@ -3166,7 +3171,7 @@ object Parsers {
tmplDef(start, mods)
}

/** PatDef ::= ids [‘:’ Type] ‘=’ Expr
/** PatDef ::= ids [‘:’ ResultType] ‘=’ Expr
* | Pattern2 [‘:’ Type | Ascription] ‘=’ Expr
* VarDef ::= PatDef | id {`,' id} `:' Type `=' `_'
* ValDcl ::= id {`,' id} `:' Type
Expand All @@ -3189,7 +3194,7 @@ object Parsers {
lhs = ascription(first, Location.ElseWhere) :: Nil
emptyType
}
else toplevelTyp()
else resultType(mods)
}
else emptyType
val rhs =
Expand Down Expand Up @@ -3218,7 +3223,7 @@ object Parsers {
}
}

/** DefDef ::= DefSig [(‘:’ | ‘<:’) Type] ‘=’ Expr
/** DefDef ::= DefSig [‘:’ ResultType] ‘=’ Expr
* | this ParamClause ParamClauses `=' ConstrExpr
* DefDcl ::= DefSig `:' Type
* DefSig ::= id [DefTypeParamClause] DefParamClauses
Expand Down Expand Up @@ -3294,12 +3299,13 @@ object Parsers {
case rparamss =>
leadingVparamss ::: rparamss
var tpt = fromWithinReturnType {
if in.token == SUBTYPE && mods.is(Inline) && AllowOldWhiteboxSyntax then
deprecationWarning("`<:` return type will no longer be supported. Use transparent modifier instead.")
in.nextToken()
mods1 = addMod(mods1, Mod.Transparent())
toplevelTyp()
else typedOpt()
if in.token == COLONEOL then in.token = COLON
// a hack to allow
//
// def f():
// T
//
typedOpt(resultType(mods))
}
if (migrateTo3) newLineOptWhenFollowedBy(LBRACE)
val rhs =
Expand Down Expand Up @@ -3532,7 +3538,7 @@ object Parsers {
syntaxError(i"extension clause can only define methods", stat.span)
}

/** GivenDef ::= [GivenSig] [‘_’ ‘<:’] Type ‘=’ Expr
/** GivenDef ::= [GivenSig] ResultType ‘=’ Expr
* | [GivenSig] ConstrApps [TemplateBody]
* GivenSig ::= [id] [DefTypeParamClause] {UsingParamClauses} ‘as’
*/
Expand All @@ -3556,14 +3562,8 @@ object Parsers {
accept(EQUALS)
mods1 |= Final
DefDef(name, tparams, vparamss, tpt, subExpr())
if in.token == USCORE && AllowOldWhiteboxSyntax then
deprecationWarning("`<:` return type will no longer be supported. Use transparent modifier instead.")
if !mods.is(Inline) then
syntaxError("`_ <:` is only allowed for given with `inline` modifier")
in.nextToken()
accept(SUBTYPE)
mods1 = addMod(mods1, Mod.Transparent())
givenAlias(toplevelTyp())
if in.token == USCORE then
givenAlias(resultType(mods))
else
val parents = constrApps(commaOK = true, templateCanFollow = true)
if in.token == EQUALS && parents.length == 1 && parents.head.isType then
Expand Down
4 changes: 4 additions & 0 deletions compiler/src/dotty/tools/dotc/transform/SymUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -223,4 +223,8 @@ class SymUtils(val self: Symbol) extends AnyVal {

def isCollectiveExtensionClass(using Context): Boolean =
self.is(ModuleClass) && self.sourceModule.is(Extension, butNot = Method)

/** The result type of this constructor */
def constructorResultType(typeParams: List[Symbol])(using Context): Type =
self.owner.typeRef.appliedTo(typeParams.map(_.typeRef))
}
9 changes: 7 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -884,10 +884,15 @@ trait Checking {

/** Check that `tree` can be right hand-side or argument to `inline` value or parameter. */
def checkInlineConformant(tpt: Tree, tree: Tree, sym: Symbol)(using Context): Unit = {
if sym.is(Inline, butNot = DeferredOrTermParamOrAccessor) && !ctx.erasedTypes && !Inliner.inInlineMethod then
if sym.is(Inline, butNot = DeferredOrTermParamOrAccessor)
&& !ctx.isAfterTyper && !Inliner.inInlineMethod
then
// final vals can be marked inline even if they're not pure, see Typer#patchFinalVals
val purityLevel = if (sym.is(Final)) Idempotent else Pure
tpt.tpe.widenTermRefExpr.dealias.normalized match
val tpe = tpt match
case TypeBoundsTree(_, _, _) => tree.tpe
case _ => tpt.tpe
tpe.widenTermRefExpr.dealias.normalized match
case tp: ConstantType =>
if !(exprPurity(tree) >= purityLevel) then
ctx.error(em"inline value must be pure", tree.sourcePos)
Expand Down
54 changes: 26 additions & 28 deletions compiler/src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,6 @@ trait NamerContextOps {
if (pkg.is(Package)) thisCtx.fresh.setOwner(pkg.moduleClass).setTree(tree)
else thisCtx

/** The given type, unless `sym` is a constructor, in which case the
* type of the constructed instance is returned
*/
def effectiveResultType(sym: Symbol, typeParams: List[Symbol], givenTp: Type): Type =
if (sym.name == nme.CONSTRUCTOR) sym.owner.typeRef.appliedTo(typeParams.map(_.typeRef))
else givenTp

/** if isConstructor, make sure it has one non-implicit parameter list */
def normalizeIfConstructor(termParamss: List[List[Symbol]], isConstructor: Boolean): List[List[Symbol]] =
if (isConstructor &&
Expand Down Expand Up @@ -1416,26 +1409,28 @@ class Namer { typer: Typer =>
* the corresponding parameter where bound parameters are replaced by
* Wildcards.
*/
def rhsProto = sym.asTerm.name collect {
case DefaultGetterName(original, idx) =>
val meth: Denotation =
if (original.isConstructorName && (sym.owner.is(ModuleClass)))
sym.owner.companionClass.info.decl(nme.CONSTRUCTOR)
def rhsProto = mdef.tpt match
case TypeBoundsTree(_, bound, _) => typedAheadType(bound).tpe
case _ => sym.asTerm.name.collect {
case DefaultGetterName(original, idx) =>
val meth: Denotation =
if (original.isConstructorName && (sym.owner.is(ModuleClass)))
sym.owner.companionClass.info.decl(nme.CONSTRUCTOR)
else
ctx.defContext(sym).denotNamed(original)
def paramProto(paramss: List[List[Type]], idx: Int): Type = paramss match {
case params :: paramss1 =>
if (idx < params.length) wildApprox(params(idx))
else paramProto(paramss1, idx - params.length)
case nil =>
WildcardType
}
val defaultAlts = meth.altsWith(_.hasDefaultParams)
if (defaultAlts.length == 1)
paramProto(defaultAlts.head.info.widen.paramInfoss, idx)
else
ctx.defContext(sym).denotNamed(original)
def paramProto(paramss: List[List[Type]], idx: Int): Type = paramss match {
case params :: paramss1 =>
if (idx < params.length) wildApprox(params(idx))
else paramProto(paramss1, idx - params.length)
case nil =>
WildcardType
}
val defaultAlts = meth.altsWith(_.hasDefaultParams)
if (defaultAlts.length == 1)
paramProto(defaultAlts.head.info.widen.paramInfoss, idx)
else
WildcardType
} getOrElse WildcardType
}.getOrElse(WildcardType)

// println(s"final inherited for $sym: ${inherited.toString}") !!!
// println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}")
Expand Down Expand Up @@ -1509,7 +1504,7 @@ class Namer { typer: Typer =>
val tptProto = mdef.tpt match {
case _: untpd.DerivedTypeTree =>
WildcardType
case TypeTree() =>
case TypeTree() | TypeBoundsTree(_, _, _) =>
checkMembersOK(inferredType, mdef.sourcePos)
case DependentTypeTree(tpFun) =>
val tpe = tpFun(paramss.head)
Expand Down Expand Up @@ -1543,7 +1538,10 @@ class Namer { typer: Typer =>
case _ =>
WildcardType
}
val mbrTpe = paramFn(checkSimpleKinded(typedAheadType(mdef.tpt, tptProto)).tpe)
val resultTpe = mdef.tpt match
case TypeBoundsTree(_, _, _) => tptProto
case _ => checkSimpleKinded(typedAheadType(mdef.tpt, tptProto)).tpe
val mbrTpe = paramFn(resultTpe)
if (ctx.explicitNulls && mdef.mods.is(JavaDefined))
JavaNullInterop.nullifyMember(sym, mbrTpe, mdef.mods.isAllOf(JavaEnumValue))
else mbrTpe
Expand Down Expand Up @@ -1593,7 +1591,7 @@ class Namer { typer: Typer =>
if (isConstructor) {
// set result type tree to unit, but take the current class as result type of the symbol
typedAheadType(ddef.tpt, defn.UnitType)
wrapMethType(ctx.effectiveResultType(sym, typeParams, NoType))
wrapMethType(sym.constructorResultType(typeParams))
}
else valOrDefDefSig(ddef, sym, typeParams, termParamss, wrapMethType)
}
Expand Down
4 changes: 3 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,9 @@ object PrepareInlineable {

/** The type ascription `rhs: tpt`, unless `original` is `transparent`. */
def wrapRHS(original: untpd.DefDef, tpt: Tree, rhs: Tree)(using Context): Tree =
if original.mods.hasMod(classOf[untpd.Mod.Transparent]) then rhs
if original.mods.hasMod(classOf[untpd.Mod.Transparent])
|| tpt.isInstanceOf[TypeBoundsTree]
then rhs
else Typed(rhs, tpt)

/** Register inline info for given inlineable method `sym`.
Expand Down
7 changes: 5 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1802,14 +1802,17 @@ class Typer extends Namer
def typedAnnotation(annot: untpd.Tree)(using Context): Tree =
typed(annot, defn.AnnotationClass.typeRef)

private def typedRHS(rhs: untpd.Tree, tpt: Tree)(using Context) =
typedExpr(rhs, tpt.tpe.widenExpr.bounds.hi)

def typedValDef(vdef: untpd.ValDef, sym: Symbol)(using Context): Tree = {
val ValDef(name, tpt, _) = vdef
completeAnnotations(vdef, sym)
if (sym.isOneOf(GivenOrImplicit)) checkImplicitConversionDefOK(sym)
val tpt1 = checkSimpleKinded(typedType(tpt))
val rhs1 = vdef.rhs match {
case rhs @ Ident(nme.WILDCARD) => rhs withType tpt1.tpe
case rhs => typedExpr(rhs, tpt1.tpe.widenExpr)
case rhs => typedRHS(rhs, tpt1)
}
val vdef1 = assignType(cpy.ValDef(vdef)(name, tpt1, rhs1), sym)
checkSignatureRepeatedParam(sym)
Expand Down Expand Up @@ -1876,7 +1879,7 @@ class Typer extends Namer
if (sym.isInlineMethod) rhsCtx.addMode(Mode.InlineableBody)
val rhs1 =
if sym.isScala2Macro then typedScala2MacroBody(ddef.rhs)(using rhsCtx)
else typedExpr(ddef.rhs, tpt1.tpe.widenExpr)(using rhsCtx)
else typedRHS(ddef.rhs, tpt1)(using rhsCtx)

if (sym.isInlineMethod)
val rhsToInline = PrepareInlineable.wrapRHS(ddef, tpt1, rhs1)
Expand Down
21 changes: 11 additions & 10 deletions docs/docs/internals/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ yield
### Soft keywords

```
as derives end extension inline on opaque open transparent using
as derives end extension inline on opaque open using
* + -
```

Expand Down Expand Up @@ -154,7 +154,7 @@ WithType ::= AnnotType {‘with’ AnnotType}
AnnotType ::= SimpleType {Annotation} Annotated(t, annot)

SimpleType ::= SimpleLiteral SingletonTypeTree(l)
| ‘?’ SubtypeBounds
| ‘?’ TypeBounds
| SimpleType ‘(’ Singletons ‘)’
| SimpleType1
SimpleType1 ::= id Ident(name)
Expand All @@ -179,8 +179,9 @@ TypeArgs ::= ‘[’ ArgTypes ‘]’
NamedTypeArg ::= id ‘=’ Type NamedArg(id, t)
NamedTypeArgs ::= ‘[’ NamedTypeArg {‘,’ NamedTypeArg} ‘]’ nts
Refinement ::= ‘{’ [RefineDcl] {semi [RefineDcl]} ‘}’ ds
SubtypeBounds ::= [‘>:’ Type] [‘<:’ Type] | INT TypeBoundsTree(lo, hi)
TypeParamBounds ::= SubtypeBounds {‘:’ Type} ContextBounds(typeBounds, tps)
TypeBounds ::= [‘>:’ Type] [‘<:’ Type] TypeBoundsTree(lo, hi)
TypeParamBounds ::= TypeBounds {‘:’ Type} ContextBounds(typeBounds, tps)
ResultType ::= [‘_’ ‘<:] Type
Types ::= Type {‘,’ Type}
```

Expand Down Expand Up @@ -297,11 +298,11 @@ DefTypeParamClause::= ‘[’ DefTypeParam {‘,’ DefTypeParam} ‘]’
DefTypeParam ::= {Annotation} id [HkTypeParamClause] TypeParamBounds

TypTypeParamClause::= ‘[’ TypTypeParam {‘,’ TypTypeParam} ‘]’
TypTypeParam ::= {Annotation} id [HkTypeParamClause] SubtypeBounds
TypTypeParam ::= {Annotation} id [HkTypeParamClause] TypeBounds

HkTypeParamClause ::= ‘[’ HkTypeParam {‘,’ HkTypeParam} ‘]’
HkTypeParam ::= {Annotation} [‘+’ | ‘-’] (id [HkTypeParamClause] | ‘_’)
SubtypeBounds
TypeBounds

ClsParamClauses ::= {ClsParamClause} [[nl] ‘(’ [‘implicit’] ClsParams ‘)’]
ClsParamClause ::= [nl] ‘(’ ClsParams ‘)’
Expand Down Expand Up @@ -370,19 +371,19 @@ VarDcl ::= ids ‘:’ Type
DefDcl ::= DefSig ‘:’ Type DefDef(_, name, tparams, vparamss, tpe, EmptyTree)
DefSig ::= id [DefTypeParamClause] DefParamClauses
| ExtParamClause {nl} [‘.’] id DefParamClauses
TypeDcl ::= id [TypeParamClause] SubtypeBounds [‘=’ Type] TypeDefTree(_, name, tparams, bound
TypeDcl ::= id [TypeParamClause] TypeBounds [‘=’ Type] TypeDefTree(_, name, tparams, bound

Def ::= ‘val’ PatDef
| ‘var’ VarDef
| ‘def’ DefDef
| ‘type’ {nl} TypeDcl
| TmplDef
| INT
PatDef ::= ids [‘:’ Type] ‘=’ Expr
PatDef ::= ids [‘:’ ResultType] ‘=’ Expr
| Pattern2 [‘:’ Type | Ascription] ‘=’ Expr PatDef(_, pats, tpe?, expr)
VarDef ::= PatDef
| ids ‘:’ Type ‘=’ ‘_’
DefDef ::= DefSig [(‘:’ | ‘<:’) Type] ‘=’ Expr DefDef(_, name, tparams, vparamss, tpe, expr)
DefDef ::= DefSig [‘:’ ResultType] ‘=’ Expr DefDef(_, name, tparams, vparamss, tpe, expr)
| ‘this’ DefParamClause DefParamClauses ‘=’ ConstrExpr DefDef(_, <init>, Nil, vparamss, EmptyTree, expr | Block)

TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef
Expand All @@ -395,7 +396,7 @@ ClassConstr ::= [ClsTypeParamClause] [ConstrMods] ClsParamClauses
ConstrMods ::= {Annotation} [AccessModifier]
ObjectDef ::= id [Template] ModuleDef(mods, name, template) // no constructor
EnumDef ::= id ClassConstr InheritClauses EnumBody EnumDef(mods, name, tparams, template)
GivenDef ::= [GivenSig] [‘_’ ‘<:’] Type ‘=’ Expr
GivenDef ::= [GivenSig] ResultType ‘=’ Expr
| [GivenSig] ConstrApps [TemplateBody]
GivenSig ::= [id] [DefTypeParamClause] {UsingParamClause} ‘as’
ExtensionDef ::= [id] [‘on’ ExtParamClause {UsingParamClause}]
Expand Down
4 changes: 2 additions & 2 deletions tests/invalid/run/typelevel-patmat.scala
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,12 @@ object Test extends App {
val e1 = nth(r2, 1)
val ce1: String = e1

inline def concatTyped(xs: HList, ys: HList) <: Typed[_ <: HList] = inline xs match {
inline def concatTyped(xs: HList, ys: HList): _ <: Typed[_ <: HList] = inline xs match {
case HNil => Typed(ys)
case HCons(x, xs1) => Typed(HCons(x, concatTyped(xs1, ys).value))
}

def concatImpl(xs: HList, ys: HList) <: HList = xs match {
def concatImpl(xs: HList, ys: HList): _ <: HList = xs match {
case HNil => ys
case HCons(x, xs1) => HCons(x, concatImpl(xs1, ys))
}
Expand Down
Loading