-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
KE2: extract binary operators #17761
Changes from 5 commits
255d5c9
bc35c50
227d302
a5fcfaf
db13b32
53460d7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -256,13 +256,14 @@ private fun KaFunctionSymbol.hasName( | |
) | ||
} | ||
|
||
private fun KaFunctionSymbol.isNumericWithName(functionName: String): Boolean { | ||
return this.hasName("kotlin", "Int", functionName) || | ||
this.hasName("kotlin", "Byte", functionName) || | ||
this.hasName("kotlin", "Short", functionName) || | ||
this.hasName("kotlin", "Long", functionName) || | ||
this.hasName("kotlin", "Float", functionName) || | ||
this.hasName("kotlin", "Double", functionName) | ||
private fun KaFunctionSymbol?.isNumericWithName(functionName: String): Boolean { | ||
return this != null && | ||
(this.hasName("kotlin", "Int", functionName) || | ||
this.hasName("kotlin", "Byte", functionName) || | ||
this.hasName("kotlin", "Short", functionName) || | ||
this.hasName("kotlin", "Long", functionName) || | ||
this.hasName("kotlin", "Float", functionName) || | ||
this.hasName("kotlin", "Double", functionName)) | ||
} | ||
|
||
context(KaSession) | ||
|
@@ -297,37 +298,83 @@ private fun KotlinFileExtractor.extractBinaryExpression( | |
val op = expression.operationToken | ||
val target = expression.resolveCallTarget()?.symbol | ||
|
||
when (op) { | ||
KtTokens.PLUS -> { | ||
if (target == null) { | ||
TODO() | ||
} | ||
|
||
if (target.isNumericWithName("plus") || | ||
target.hasName("kotlin", "String", "plus") || | ||
target.hasMatchingNames( | ||
CallableId(FqName("kotlin"), null, Name.identifier("plus")), | ||
ClassId(FqName("kotlin"), Name.identifier("String")), | ||
nullability = KaTypeNullability.NULLABLE, | ||
) | ||
) { | ||
val id = tw.getFreshIdLabel<DbAddexpr>() | ||
val type = useType(expression.expressionType) | ||
val exprParent = parent.expr(expression, callable) | ||
tw.writeExprs_addexpr(id, type.javaResult.id, exprParent.parent, exprParent.idx) | ||
tw.writeExprsKotlinType(id, type.kotlinResult.id) | ||
|
||
extractExprContext(id, tw.getLocation(expression), callable, exprParent.enclosingStmt) | ||
extractExpressionExpr(expression.left!!, callable, id, 0, exprParent.enclosingStmt) | ||
extractExpressionExpr(expression.right!!, callable, id, 1, exprParent.enclosingStmt) | ||
} else { | ||
TODO("Extract as method call") | ||
if (op == KtTokens.PLUS && target.isBinaryPlus()) { | ||
extractBinaryExpression(expression, callable, parent, tw::writeExprs_addexpr) | ||
} else if (op == KtTokens.MINUS && target.isNumericWithName("minus")) { | ||
extractBinaryExpression(expression, callable, parent, tw::writeExprs_subexpr) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So far at least this is very regular; I wonder if it would be worth writing as
? And either way, something like
might be nicer than a big if/elseif There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here's the followup refactoring PR: #17974 |
||
} else if (op == KtTokens.MUL && target.isNumericWithName("times")) { | ||
extractBinaryExpression(expression, callable, parent, tw::writeExprs_mulexpr) | ||
} else if (op == KtTokens.DIV && target.isNumericWithName("div")) { | ||
extractBinaryExpression(expression, callable, parent, tw::writeExprs_divexpr) | ||
} else if (op == KtTokens.PERC && target.isNumericWithName("rem")) { | ||
extractBinaryExpression(expression, callable, parent, tw::writeExprs_remexpr) | ||
} else if (op == KtTokens.IDENTIFIER && target.isNumericWithName("and")) { | ||
extractBinaryExpression(expression, callable, parent, tw::writeExprs_andbitexpr) | ||
} else if (op == KtTokens.IDENTIFIER && target.isNumericWithName("or")) { | ||
extractBinaryExpression(expression, callable, parent, tw::writeExprs_orbitexpr) | ||
} else if (op == KtTokens.IDENTIFIER && target.isNumericWithName("xor")) { | ||
extractBinaryExpression(expression, callable, parent, tw::writeExprs_xorbitexpr) | ||
} else if (op == KtTokens.IDENTIFIER && target.isNumericWithName("shl")) { | ||
extractBinaryExpression(expression, callable, parent, tw::writeExprs_lshiftexpr) | ||
} else if (op == KtTokens.IDENTIFIER && target.isNumericWithName("shr")) { | ||
extractBinaryExpression(expression, callable, parent, tw::writeExprs_rshiftexpr) | ||
} else if (op == KtTokens.IDENTIFIER && target.isNumericWithName("ushr")) { | ||
extractBinaryExpression(expression, callable, parent, tw::writeExprs_urshiftexpr) | ||
} else if (op == KtTokens.EQEQEQ && target == null) { | ||
extractBinaryExpression(expression, callable, parent, tw::writeExprs_eqexpr) | ||
} else if (op == KtTokens.EXCLEQEQEQ && target == null) { | ||
extractBinaryExpression(expression, callable, parent, tw::writeExprs_neexpr) | ||
} else if (op in listOf(KtTokens.LT, KtTokens.GT, KtTokens.LTEQ, KtTokens.GTEQ)) { | ||
if (target.isNumericWithName("compareTo")) { | ||
when (op) { | ||
KtTokens.LT -> extractBinaryExpression(expression, callable, parent, tw::writeExprs_ltexpr) | ||
KtTokens.GT -> extractBinaryExpression(expression, callable, parent, tw::writeExprs_gtexpr) | ||
KtTokens.LTEQ -> extractBinaryExpression(expression, callable, parent, tw::writeExprs_leexpr) | ||
KtTokens.GTEQ -> extractBinaryExpression(expression, callable, parent, tw::writeExprs_geexpr) | ||
else -> TODO("error") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we're changing this to just return |
||
} | ||
} else { | ||
TODO("Extract lowered equivalent call, such as `a.compareTo(b) < 0`") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, but my previous suggestion won't work if we need to do something special in this case. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we need the comment. Instead we should merge this too: #17939 |
||
} | ||
|
||
else -> TODO() | ||
} else { | ||
// todo: other operators, such as .., ..<, in, !in, =, +=, -=, *=, /=, %=, ==, !=, | ||
TODO("Extract as method call") | ||
} | ||
} | ||
|
||
private fun KaFunctionSymbol?.isBinaryPlus(): Boolean { | ||
return this != null && ( | ||
this.isNumericWithName("plus") || | ||
this.hasName("kotlin", "String", "plus") || | ||
this.hasMatchingNames( | ||
CallableId(FqName("kotlin"), null, Name.identifier("plus")), | ||
ClassId(FqName("kotlin"), Name.identifier("String")), | ||
nullability = KaTypeNullability.NULLABLE, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be worth adding a comment saying what this last case corresponds to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can dig that up, but this bit was just refactored. It was originally introduced in #17752 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comment added in 53460d7. |
||
)) | ||
} | ||
|
||
context(KaSession) | ||
private fun <T : DbBinaryexpr> KotlinFileExtractor.extractBinaryExpression( | ||
expression: KtBinaryExpression, | ||
callable: Label<out DbCallable>, | ||
parent: StmtExprParent, | ||
extractExpression: ( | ||
id: Label<out T>, | ||
typeid: Label<out DbType>, | ||
parent: Label<out DbExprparent>, | ||
idx: Int | ||
) -> Unit | ||
) { | ||
val id = tw.getFreshIdLabel<T>() | ||
val type = useType(expression.expressionType) | ||
val exprParent = parent.expr(expression, callable) | ||
extractExpression(id, type.javaResult.id, exprParent.parent, exprParent.idx) | ||
tw.writeExprsKotlinType(id, type.kotlinResult.id) | ||
|
||
extractExprContext(id, tw.getLocation(expression), callable, exprParent.enclosingStmt) | ||
extractExpressionExpr(expression.left!!, callable, id, 0, exprParent.enclosingStmt) | ||
extractExpressionExpr(expression.right!!, callable, id, 1, exprParent.enclosingStmt) | ||
} | ||
|
||
context(KaSession) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the plan for
target == null
?If we're just going to emit an
errorExpr
, and perhaps add some more info in a supplementary table, then can we handle that case first, and makeisNumericWithName
andisBinaryPlus
take a non-null KaFunctionSymbol and not have to handle thenull
case?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are cases below where target is null, for example in case of
===
.