Skip to content

Commit

Permalink
Merge pull request #25966 from rdhananjaya/unify-obj-method-field-scopes
Browse files Browse the repository at this point in the history
Unify object method scope and object field scope
  • Loading branch information
hasithaa authored Oct 20, 2020
2 parents 25d759e + 1007edc commit 6252d16
Show file tree
Hide file tree
Showing 20 changed files with 298 additions and 91 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -374,11 +374,7 @@ private void defineFunction(DataInputStream dataInStream) throws IOException {
invokableSymbol.name =
names.fromString(Symbols.getAttachedFuncSymbolName(attachedType.tsymbol.name.value, funcName));
if (attachedType.tag == TypeTags.OBJECT || attachedType.tag == TypeTags.RECORD) {
if (attachedType.tag == TypeTags.OBJECT) {
scopeToDefine = ((BObjectTypeSymbol) attachedType.tsymbol).methodScope;
} else {
scopeToDefine = attachedType.tsymbol.scope;
}
scopeToDefine = attachedType.tsymbol.scope;
BAttachedFunction attachedFunc =
new BAttachedFunction(names.fromString(funcName), invokableSymbol, funcType,
symTable.builtinPos);
Expand Down Expand Up @@ -1279,7 +1275,6 @@ public BType readType(int cpI) throws IOException {
env.pkgSymbol, symTable.builtinPos,
COMPILED_SOURCE);
objectSymbol.scope = new Scope(objectSymbol);
objectSymbol.methodScope = new Scope(objectSymbol);
BObjectType objectType;
// Below is a temporary fix, need to fix this properly by using the type tag
if (service) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ private ClosureDesugar(CompilerContext context) {
public void visit(BLangPackage pkgNode) {
SymbolEnv pkgEnv = this.symTable.pkgEnvMap.get(pkgNode.symbol);

// Process nodes that are not lambdas
pkgNode.topLevelNodes.stream().filter(pkgLevelNode -> !(pkgLevelNode.getKind() == NodeKind.FUNCTION
&& ((BLangFunction) pkgLevelNode).flagSet.contains(Flag.LAMBDA))).forEach(
topLevelNode -> rewrite((BLangNode) topLevelNode, pkgEnv));
Expand Down Expand Up @@ -1375,7 +1376,6 @@ public void visit(BLangAnnotAccessExpr annotAccessExpr) {

@Override
public void visit(BLangStatementExpression bLangStatementExpression) {
bLangStatementExpression.expr = rewriteExpr(bLangStatementExpression.expr);
if (bLangStatementExpression.stmt.getKind() == NodeKind.BLOCK) {
BLangBlockStmt bLangBlockStmt = (BLangBlockStmt) bLangStatementExpression.stmt;
for (int i = 0; i < bLangBlockStmt.stmts.size(); i++) {
Expand All @@ -1385,6 +1385,7 @@ public void visit(BLangStatementExpression bLangStatementExpression) {
} else {
bLangStatementExpression.stmt = rewrite(bLangStatementExpression.stmt, env);
}
bLangStatementExpression.expr = rewriteExpr(bLangStatementExpression.expr);
result = bLangStatementExpression;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@
import org.wso2.ballerinalang.compiler.tree.types.BLangUnionTypeNode;
import org.wso2.ballerinalang.compiler.tree.types.BLangUserDefinedType;
import org.wso2.ballerinalang.compiler.tree.types.BLangValueType;
import org.wso2.ballerinalang.compiler.util.ClosureVarSymbol;
import org.wso2.ballerinalang.compiler.util.CompilerContext;
import org.wso2.ballerinalang.compiler.util.FieldKind;
import org.wso2.ballerinalang.compiler.util.Name;
Expand Down Expand Up @@ -285,9 +286,11 @@
import static org.wso2.ballerinalang.compiler.desugar.ASTBuilderUtil.createBlockStmt;
import static org.wso2.ballerinalang.compiler.desugar.ASTBuilderUtil.createErrorVariableDef;
import static org.wso2.ballerinalang.compiler.desugar.ASTBuilderUtil.createExpressionStmt;
import static org.wso2.ballerinalang.compiler.desugar.ASTBuilderUtil.createIdentifier;
import static org.wso2.ballerinalang.compiler.desugar.ASTBuilderUtil.createLiteral;
import static org.wso2.ballerinalang.compiler.desugar.ASTBuilderUtil.createStatementExpression;
import static org.wso2.ballerinalang.compiler.desugar.ASTBuilderUtil.createVariable;
import static org.wso2.ballerinalang.compiler.desugar.ASTBuilderUtil.createVariableRef;
import static org.wso2.ballerinalang.compiler.util.Constants.INIT_METHOD_SPLIT_SIZE;
import static org.wso2.ballerinalang.compiler.util.Names.GEN_VAR_PREFIX;
import static org.wso2.ballerinalang.compiler.util.Names.IGNORE;
Expand Down Expand Up @@ -1695,7 +1698,7 @@ private BLangLambdaFunction generateEntriesToMapLambda(DiagnosticPos pos) {
ASTBuilderUtil.createIndexBasesAccessExpr(pos, symTable.anyType, keyValSymbol,
ASTBuilderUtil
.createLiteral(pos, symTable.intType, (long) 1));
BLangSimpleVariableDef tupSecondElem = createVarDef("val", indexBasesAccessExpr.type,
BLangSimpleVariableDef tupSecondElem = createVarDef("$val", indexBasesAccessExpr.type,
indexBasesAccessExpr, pos);
functionBlock.addStatement(tupSecondElem);

Expand Down Expand Up @@ -1904,7 +1907,7 @@ private BLangLambdaFunction createFuncToFilterOutRestParam(List<String> toRemove
BLangIndexBasedAccess indexBasesAccessExpr =
ASTBuilderUtil.createIndexBasesAccessExpr(pos, symTable.anyType, keyValSymbol, ASTBuilderUtil
.createLiteral(pos, symTable.intType, (long) 0));
BLangSimpleVariableDef tupFirstElem = createVarDef("key", indexBasesAccessExpr.type,
BLangSimpleVariableDef tupFirstElem = createVarDef("$key", indexBasesAccessExpr.type,
indexBasesAccessExpr, pos);
functionBlock.addStatement(tupFirstElem);

Expand Down Expand Up @@ -3794,7 +3797,8 @@ public void visit(BLangFieldBasedAccess fieldAccessExpr) {
((BUnionType) varRefType).getMemberTypes().iterator().next().tag == TypeTags.OBJECT)) {
if (fieldAccessExpr.symbol != null && fieldAccessExpr.symbol.type.tag == TypeTags.INVOKABLE &&
((fieldAccessExpr.symbol.flags & Flags.ATTACHED) == Flags.ATTACHED)) {
targetVarRef = new BLangStructFunctionVarRef(fieldAccessExpr.expr, (BVarSymbol) fieldAccessExpr.symbol);
result = rewriteObjectMemberAccessAsField(fieldAccessExpr);
return;
} else {
boolean isStoreOnCreation = fieldAccessExpr.isStoreOnCreation;

Expand Down Expand Up @@ -3853,6 +3857,127 @@ public void visit(BLangFieldBasedAccess fieldAccessExpr) {
result = targetVarRef;
}

private BLangNode rewriteObjectMemberAccessAsField(BLangFieldBasedAccess fieldAccessExpr) {
DiagnosticPos pos = fieldAccessExpr.pos;
BInvokableSymbol originalMemberFuncSymbol = (BInvokableSymbol) fieldAccessExpr.symbol;
// Can we cache this?
BLangFunction func = (BLangFunction) TreeBuilder.createFunctionNode();
String funcName = "$annon$method$delegate$" + lambdaFunctionCount++;
BInvokableSymbol funcSymbol = new BInvokableSymbol(SymTag.INVOKABLE, (Flags.ANONYMOUS | Flags.LAMBDA),
names.fromString(funcName),
env.enclPkg.packageID, originalMemberFuncSymbol.type, env.scope.owner, pos, VIRTUAL);
funcSymbol.retType = originalMemberFuncSymbol.retType;
funcSymbol.bodyExist = true;
funcSymbol.params = new ArrayList<>();
funcSymbol.scope = new Scope(funcSymbol);
func.pos = pos;
func.name = createIdentifier(pos, funcName);
func.flagSet.add(Flag.LAMBDA);
func.flagSet.add(Flag.ANONYMOUS);
func.body = (BLangBlockFunctionBody) TreeBuilder.createBlockFunctionBodyNode();
func.symbol = funcSymbol;
func.type = funcSymbol.type;
func.closureVarSymbols = new LinkedHashSet<>();
// When we are supporting non var ref exprs we need to create a def, assign, get the ref and use it here.
BLangExpression receiver = fieldAccessExpr.expr;
// This is used to keep the tempary var def, when the receiver is a expression we need to have a
// vardef in encl invocable and we can cosider that receiver is taken as a closure var.
BLangSimpleVariableDef intermediateObjDef = null;
if (receiver.getKind() == NodeKind.SIMPLE_VARIABLE_REF) {
BSymbol receiverSymbol = ((BLangVariableReference) receiver).symbol;
receiverSymbol.closure = true;
func.closureVarSymbols.add(new ClosureVarSymbol(receiverSymbol, pos));
} else {
BLangSimpleVariableDef varDef = createVarDef("$$temp$obj$" + annonVarCount++, receiver.type, receiver, pos);
intermediateObjDef = varDef;
varDef.var.symbol.closure = true;
env.scope.define(varDef.var.symbol.name, varDef.var.symbol);
BLangSimpleVarRef variableRef = createVariableRef(pos, varDef.var.symbol);
func.closureVarSymbols.add(new ClosureVarSymbol(varDef.var.symbol, pos));
receiver = variableRef;
}

// todo: handle taint table; issue: https://github.com/ballerina-platform/ballerina-lang/issues/25962

ArrayList<BLangExpression> requiredArgs = new ArrayList<>();
for (BVarSymbol param : originalMemberFuncSymbol.params) {
BLangSimpleVariable fParam = (BLangSimpleVariable) TreeBuilder.createSimpleVariableNode();
fParam.symbol = new BVarSymbol(0, param.name, env.enclPkg.packageID, param.type, funcSymbol, pos,
VIRTUAL);
fParam.pos = pos;
fParam.name = createIdentifier(pos, param.name.value);
fParam.type = param.type;
func.requiredParams.add(fParam);
funcSymbol.params.add(fParam.symbol);
funcSymbol.scope.define(fParam.symbol.name, fParam.symbol);

BLangSimpleVarRef paramRef = createVariableRef(pos, fParam.symbol);
requiredArgs.add(paramRef);
}

ArrayList<BLangExpression> restArgs = new ArrayList<>();
if (originalMemberFuncSymbol.restParam != null) {
BLangSimpleVariable restParam = (BLangSimpleVariable) TreeBuilder.createSimpleVariableNode();
func.restParam = restParam;
BVarSymbol restSym = originalMemberFuncSymbol.restParam;
restParam.name = ASTBuilderUtil.createIdentifier(pos, restSym.name.value);
restParam.symbol = new BVarSymbol(0, restSym.name, env.enclPkg.packageID, restSym.type, funcSymbol, pos,
VIRTUAL);
restParam.pos = pos;
restParam.type = restSym.type;
funcSymbol.restParam = restParam.symbol;
funcSymbol.scope.define(restParam.symbol.name, restParam.symbol);

BLangSimpleVarRef restArg = createVariableRef(pos, restParam.symbol);
BLangRestArgsExpression restArgExpr = new BLangRestArgsExpression();
restArgExpr.expr = restArg;
restArgExpr.pos = pos;
restArgExpr.type = restSym.type;
restArgExpr.expectedType = restArgExpr.type;
restArgs.add(restArgExpr);
}

BLangIdentifier field = fieldAccessExpr.field;
BLangReturn retStmt = (BLangReturn) TreeBuilder.createReturnNode();
retStmt.expr = createObjectMethodInvocation(
receiver, field, fieldAccessExpr.symbol, requiredArgs, restArgs);
((BLangBlockFunctionBody) func.body).addStatement(retStmt);

BLangLambdaFunction lambdaFunction = (BLangLambdaFunction) TreeBuilder.createLambdaFunctionNode();
lambdaFunction.function = func;
lambdaFunction.capturedClosureEnv = env.createClone();
env.enclPkg.functions.add(func);
env.enclPkg.topLevelNodes.add(func);
//env.enclPkg.lambdaFunctions.add(lambdaFunction);
lambdaFunction.parent = env.enclInvokable;
lambdaFunction.type = func.type;

if (intermediateObjDef == null) {
return rewrite(lambdaFunction, env);
} else {
BLangStatementExpression expr = createStatementExpression(intermediateObjDef, rewrite(lambdaFunction, env));
expr.type = lambdaFunction.type;
return rewrite(expr, env);
}
}

private BLangInvocation createObjectMethodInvocation(BLangExpression receiver, BLangIdentifier field,
BSymbol invocableSymbol,
List<BLangExpression> requiredArgs,
List<BLangExpression> restArgs) {
BLangInvocation invocationNode = (BLangInvocation) TreeBuilder.createInvocationNode();
invocationNode.name = field;
invocationNode.pkgAlias = (BLangIdentifier) TreeBuilder.createIdentifierNode();

invocationNode.expr = receiver;

invocationNode.symbol = invocableSymbol;
invocationNode.type = ((BInvokableType) invocableSymbol.type).retType;
invocationNode.requiredArgs = requiredArgs;
invocationNode.restArgs = restArgs;
return invocationNode;
}

private BLangStatementExpression rewriteLaxMapAccess(BLangFieldBasedAccess fieldAccessExpr) {
BLangStatementExpression statementExpression = new BLangStatementExpression();
BLangBlockStmt block = new BLangBlockStmt();
Expand Down Expand Up @@ -3907,7 +4032,7 @@ private BLangStatementExpression rewriteLaxMapAccess(BLangFieldBasedAccess field
errorCtorArgs.add(message);

BLangSimpleVariableDef errorDef =
createVarDef("_$_invalid_key_error", symTable.errorType, errorInvocation, pos);
createVarDef("$_invalid_key_error", symTable.errorType, errorInvocation, pos);
resultNilBody.addStatement(errorDef);

BLangSimpleVarRef errorRef = ASTBuilderUtil.createVariableRef(pos, errorDef.var.symbol);
Expand Down Expand Up @@ -4292,12 +4417,12 @@ private BLangInvocation desugarStreamTypeInit(BLangTypeInit typeInitExpr) {

private BLangSimpleVariableDef createVarDef(String name, BType type, BLangExpression expr, DiagnosticPos pos) {
BSymbol objSym = symResolver.lookupSymbolInMainSpace(env, names.fromString(name));
// todo: check and remove this bit here
if (objSym == null || objSym == symTable.notFoundSymbol) {
objSym = new BVarSymbol(0, names.fromString(name), this.env.scope.owner.pkgID, type,
this.env.scope.owner, pos, VIRTUAL);
}
BLangSimpleVariable objVar = ASTBuilderUtil.createVariable(pos, "$" + name + "$", type, expr,
(BVarSymbol) objSym);
BLangSimpleVariable objVar = ASTBuilderUtil.createVariable(pos, name, type, expr, (BVarSymbol) objSym);
BLangSimpleVariableDef objVarDef = ASTBuilderUtil.createVariableDef(pos);
objVarDef.var = objVar;
objVarDef.type = objVar.type;
Expand Down Expand Up @@ -5588,9 +5713,6 @@ private BLangInvocation createLangLibInvocationNode(String functionName,
invocationNode.pkgAlias = (BLangIdentifier) TreeBuilder.createIdentifierNode();

invocationNode.expr = onExpr;



invocationNode.symbol = symResolver.lookupLangLibMethod(onExpr.type, names.fromString(functionName));

ArrayList<BLangExpression> requiredArgs = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import org.wso2.ballerinalang.compiler.semantics.model.SymbolEnv;
import org.wso2.ballerinalang.compiler.semantics.model.SymbolTable;
import org.wso2.ballerinalang.compiler.semantics.model.symbols.BInvokableSymbol;
import org.wso2.ballerinalang.compiler.semantics.model.symbols.BObjectTypeSymbol;
import org.wso2.ballerinalang.compiler.semantics.model.symbols.SymTag;
import org.wso2.ballerinalang.compiler.semantics.model.symbols.Symbols;
import org.wso2.ballerinalang.compiler.tree.BLangBlockFunctionBody;
Expand Down Expand Up @@ -112,7 +111,7 @@ private void rewriteListenerLifeCycleFunction(BLangFunction lifeCycleFunction, B
final Name functionName = names
.fromString(Symbols.getAttachedFuncSymbolName(variable.type.tsymbol.name.value, method));
BInvokableSymbol methodInvocationSymbol = (BInvokableSymbol) symResolver
.lookupMemberSymbol(pos, ((BObjectTypeSymbol) variable.type.tsymbol).methodScope, env, functionName,
.lookupMemberSymbol(pos, variable.type.tsymbol.scope, env, functionName,
SymTag.INVOKABLE);

BLangSimpleVarRef varRef = ASTBuilderUtil.createVariableRef(pos, variable.symbol);
Expand Down Expand Up @@ -163,7 +162,7 @@ void rewriteServiceVariable(BLangService service, SymbolEnv env, BLangBlockStmt
final Name functionName = names
.fromString(Symbols.getAttachedFuncSymbolName(attachExpr.type.tsymbol.name.value, ATTACH_METHOD));
BInvokableSymbol methodRef = (BInvokableSymbol) symResolver
.lookupMemberSymbol(pos, ((BObjectTypeSymbol) listenerVarRef.type.tsymbol).methodScope, env,
.lookupMemberSymbol(pos, listenerVarRef.type.tsymbol.scope, env,
functionName, SymTag.INVOKABLE);

// Create method invocation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.wso2.ballerinalang.compiler.semantics.model.SymbolEnv;
import org.wso2.ballerinalang.compiler.semantics.model.SymbolTable;
import org.wso2.ballerinalang.compiler.semantics.model.symbols.BInvokableSymbol;
import org.wso2.ballerinalang.compiler.semantics.model.symbols.BObjectTypeSymbol;
import org.wso2.ballerinalang.compiler.semantics.model.symbols.BSymbol;
import org.wso2.ballerinalang.compiler.semantics.model.symbols.SymTag;
import org.wso2.ballerinalang.compiler.semantics.model.symbols.Symbols;
Expand Down Expand Up @@ -1876,7 +1877,7 @@ private void checkFinalObjectFieldUpdate(BLangFieldBasedAccess fieldAccess) {
BType exprType = expr.type;

if (types.isSubTypeOfBaseType(exprType, TypeTags.OBJECT) &&
isFinalFieldInAllObjects(exprType, fieldAccess.field.value)) {
isFinalFieldInAllObjects(fieldAccess.pos, exprType, fieldAccess.field.value)) {
dlog.error(fieldAccess.pos, DiagnosticCode.CANNOT_UPDATE_FINAL_OBJECT_FIELD, fieldAccess.field.value);
return;
}
Expand All @@ -1888,13 +1889,24 @@ private void checkFinalObjectFieldUpdate(BLangFieldBasedAccess fieldAccess) {
checkFinalObjectFieldUpdate((BLangFieldBasedAccess) expr);
}

private boolean isFinalFieldInAllObjects(BType type, String fieldName) {
private boolean isFinalFieldInAllObjects(DiagnosticPos pos, BType type, String fieldName) {
if (type.tag == TypeTags.OBJECT) {
return Symbols.isFlagOn(((BObjectType) type).fields.get(fieldName).symbol.flags, Flags.FINAL);

BField field = ((BObjectType) type).fields.get(fieldName);
if (field != null) {
return Symbols.isFlagOn(field.symbol.flags, Flags.FINAL);
}

BObjectTypeSymbol objTypeSymbol = (BObjectTypeSymbol) type.tsymbol;
Name funcName = names.fromString(Symbols.getAttachedFuncSymbolName(objTypeSymbol.name.value, fieldName));
BSymbol funcSymbol = symResolver.resolveObjectMethod(pos, env, funcName, objTypeSymbol);

// Object member functions are inherently final
return funcSymbol != null;
}

for (BType memberType : ((BUnionType) type).getMemberTypes()) {
if (!isFinalFieldInAllObjects(memberType, fieldName)) {
if (!isFinalFieldInAllObjects(pos, memberType, fieldName)) {
return false;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ private BSymbol resolveFullyQualifiedSymbol(DiagnosticPos pos, SymbolEnv env, St
// `pkgEnv` is `env` if no package was identified or else it's the package's environment
String functionID = typeName + "." + identifierName;
Name functionName = names.fromString(functionID);
return symResolver.lookupMemberSymbol(pos, objectTypeSymbol.methodScope, pkgEnv, functionName, tag);
return symResolver.lookupMemberSymbol(pos, objectTypeSymbol.scope, pkgEnv, functionName, tag);
}

return symTable.notFoundSymbol;
Expand Down
Loading

0 comments on commit 6252d16

Please sign in to comment.